defer以下几个特性,使用时需要关注下。
os.Exit()
时defer不会被执行定义defer时传入的参数,是作为拷贝传递的。
也就是说,如果原来的变量值发生变化,不会影响传给defer的参数。
例子如下:
package main
import (
"fmt"
)
func main(){
test()
}
func test() {
a := 0
defer func (i int) {
fmt.Println("in defer i:", i)
}(a)
a += 1
fmt.Println("a:", a)
}
输出结果:
a: 1
in defer i: 0
可以看到,即使变量a发生变化,延迟执行时变量的值仍然是0,与定义defer时传入的值一样。
os.Exit()
时defer不会被执行当发生panic时,defer会被执行,但是当调用os.Exit()方法退出程序时,defer并不会被执行。
package main
import (
"fmt"
"os"
)
func main(){
fmt.Println("main start")
test()
}
func test() () {
defer func () {
fmt.Println("in defer ... ")
}()
os.Exit(0)
}
输出结果:
main start
defer定义的内容没有输出。
先来看两个例子:一个是返回匿名变量,一个是返回命名变量。
package main
import (
"fmt"
)
func main(){
i := test()
fmt.Println("main i:", i)
}
func test() int {
a := 0
defer func () {
a = 2
}()
a = 1
return a
}
定义a为0, 接着修改为1,最后在defer中将a修改为2。
在main中返回的值仍然是1.
输出结果:
main i: 1
package main
import (
"fmt"
)
func main(){
i := test()
fmt.Println("main i:", i)
}
func test() (a int) {
defer func () {
a = 2
}()
a = 1
return a
}
defer中修改a为2,能够返回给调用方。
输出结果:
main i: 2
实际上,defer 函数的执行既不是在 return 之后也不是在 return 之前,而是 return 语句包含了对 defer 函数的调用,即 return 会被翻译成如下几条伪指令:
保存返回值到栈上(如果是匿名变量,需要定义变量并赋值)
调用defer函数(如果有defer函数,则调用并执行)
调整函数栈
retq指令返回(如果是匿名变量,直接返回新定义的变量,如果是命名变量,直接返回命名变量)
命名变量返回时,不会创建新的变量,所以defer的修改会返回去。
而匿名变量,会创建新的变量,defer中的修改,还是修改原来的变量,所以修改不能返回去。
https://juejin.im/post/5b9b4acde51d450e5071d51f
https://my.oschina.net/henrylee2cn/blog/505535
原文:https://www.cnblogs.com/lanyangsh/p/11074304.html