defer函数

1、defer函数参数即时求值

func g(i int) {
   fmt.Println("g i:", i)
}
func f() {
   i := 100
   defer g(i)  //1
   fmt.Println("begin i:", i)
   i = 200
   fmt.Println("end i:", i)
   return
}

会输出begin i :100,end i: 200,最后输出g i:100

g()函数延迟执行,参数不会

2、反序调用

func f() {
   defer fmt.Println("defer01")
   fmt.Println("begin")
   defer fmt.Println("defer02")
   fmt.Println("----")
   defer fmt.Println("defer03")
   fmt.Println("end")
   return
}
begin
----
end
defer03
defer02
defer01

3、defer与return

defer 函数的执行既不是在 return 之后也不是在 return 之前,而是一条go语言的 return 语句包含了对 defer 函数的调用,给你举个例子:

package main
 
import "fmt"
 
var g = 100
 
func f() (r int) {
    defer func() {
        g = 200
    }()
 
    fmt.Printf("f: g = %d\n", g)
 
    return g
}
 
func main() {
    i := f()
    fmt.Printf("main: i = %d, g = %d\n", i, g)
}

输出g =100,i =100, g =200

这个简单理解,看看下一个例子

package main
 
import "fmt"
 
var g = 100
 
func f() (r int) {
    r = g
    defer func() {
        r = 200
    }()
 
    fmt.Printf("f: r = %d\n", r)
 
    r = 0
    return r
}
 
func main() {
    i := f()
    fmt.Printf("main: i = %d, g = %d\n", i, g)
}

输出:

r =100

i =200, g =100

看起来很冲突的结果,到汇编层面来看,用gdb层面来看,我看不懂,直接说结论

defer 函数的执行既不是在 return 之后也不是在 return 之前,而是一条go语言的 return 语句包含了对 defer 函数的调用,即 return 会被翻译成如下几条伪指令

保存返回值到栈上
调用defer函数
调整函数栈
retq指令返回

自己的理解:return有两个步骤,把值放到栈里面,然后在return退出函数栈第一个例子return g是先g把值赋值给r,然后r的值放栈里面,g值的改变无关了,第二个例子是因为r的值放到栈里面,但是后来defer的时候r 的值改变了,所以最后return的时候r=200。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!