Go语言defer的作用域为当前函数
10 Jan 2023 -
Go官方对defer关键字的行为解释,第一句是:
A “defer” statement invokes a function whose execution is deferred to the moment the surrounding function returns
defer的作用域是一个函数,在函数退出时立即调用。
在任何{ }包围的区间里写defer,效果等同于在该执行点注册一次defer。
1 在循环和if语句中注册defer
考虑下面的代码会打印什么内容?
package main
import "fmt"
func main() {
i := 0
for {
defer func(itr int) {
fmt.Printf("finish loop %d\n", itr)
}(i)
if i > 5 {
break
}
i++
}
if i > 5 {
defer fmt.Printf("finish if\n")
fmt.Printf("Yes\n")
}
fmt.Printf("end proc\n")
}
结果是,先打印”Yes”和”end proc”,之后再按照defer注册的逆序打印相应内容,即defer的调用顺序。如下:
Yes
end proc
finish if
finish loop 6
finish loop 5
finish loop 4
finish loop 3
finish loop 2
finish loop 1
finish loop 0
2 在多次运行行为不同的代码块中注册defer
现在考虑如下代码。和上面的if语句不同的是,由于rand存在,程序每次运行的行为都可能与上一次不同。
那么defer的注册是否也可以是有选择的呢?
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixMicro())
r := rand.Int()
if r%2 == 1 {
defer fmt.Printf("random number is odd\n")
}
fmt.Printf("end proc, r%%2 = %v\n", r%2)
}
程序运行两次,产生不同的随机数与不同的行为:
end proc, r%2 = 1
random number is odd
end proc, r%2 = 0
所以可以得出结论,defer在代码块中的注册也是有选择的,
没有运行到的代码是不会对defer注册的。