defer 关键字在我们日常开发中是出现频率极高的。
defer语句用于延迟调用指定的函数,比如释放资源,锁释放等。
如下,database操作完成后断开链接(随手写的代码)。
func process() {
cli,err := db.connect("url")
if err != nil{
log.Fatal(err)
}
defer cli.disconnect()
cli.insert(.....)
}
但是defer也是一道辣嗓子的菜,不好好掌握是会在面试时吃大亏的。
第一题
type number int
func main(){
var v number = 0
v.Print(1)
defer v.Print(2).Print(3)
v.Print(4)
}
func (n number) Print(a number) number{
fmt.Println(a)
return n
}
输出结果:1 2 4 3
解析:
1.先执行第6行,所以输出1 没有问题
2.defer 语句入栈前需要对参数求值, 这里的参数指的是 Print(3)的调用者 -> v.Print(2), 在求 v.Print(2)的返回值时会输出 2. 所以第二个值是 2. 然后2.Print(3) 入栈等待执行
3. 执行第10行 输出 4
4.执行 defer的语句 2.Print(3) 输出 3
简单版
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
输出结果:0
第二题
func main(){
fmt.Print(f())
}
func f() (res int) {
defer func() {
res++
}()
return 0
}
输出结果:1
解析:
1. golang的return操作是非原子性的,所以return 0 可以理解为 result = 0,return result
2. 在执行 return result(0)后,defer 对 result ++, 所以 result = 1,输出 1
我们可以把f() 理解成这样
func f() (res int) {
res = 0
func(){
res ++
}()
return res
}
第三题
func main() {
fmt.Print(f())
}
func f() (res int) {
num := 1
defer func() {
num += 3
}()
return num
}
输出结果:1
解析:
该题与第二题其实原因一样。我们可以把 f() 理解成
func f() (res int) {
num := 1
res = num
func() {
num += 3
}()
return res
}
所以 t 的修改对 result 值本身没有任何影响,也就不影响最终的返回结果了
第四题
func main() {
fmt.Print(f())
}
func f() (res int) {
defer func(r int) {
r = r + 5
}(res)
return 1
}
输出结果: 1, 可能这个是大家最不能理解的了
解析:
1. 我们先按照前两题解题方式重写函数来理解,像这样
func f() (res int) {
res = 1
func(num int){
num += 5
}(res)
return res
}
2. 题目原代码第5行的 r 是 传入的 result 的副本。 也就是说,r 的修改不影响 result 的值。
总结
1. defer 是在 函数返回前 执行
2. return的操作是非原子性的
3. defer 语句会在入栈前求出 参数的具体值
到此结束。
有问题,或者建议请留言,谢谢。