1. 实现原理
在Go1.14的编译器中,会把函数中的defer语句直接插入到函数尾部,在函数内直接展开defer语句并调用
func f() {
defer fmt.Println("A")
fmt.Println("B")
return
}
func f() {
fmt.Println("B")
fmt.Println("A")
return
}
2. 经典例子
思考一下,以下函数分别输出什么?
func f1() int {
i := 0
defer func(){
i++
}()
return i
}
func f2() (i int) {
defer func(){
i++
}()
return i
}
按照刚才说的原理,应该输出1,1。实际上却输出了0,1
为什么?
3. 与return之间的执行顺序
return的执行是分两步的,第一步,赋值给返回变量;第二步,返回返回变量,而defer是在第一步之后执行。
现在来看看f1,在执行return i时,由于是匿名返回,所以会创建一个临时变量并把 i 赋值给它,temp = i,
然后执行defer中的i++,最后返回temp,因为返回的temp,所以i修改不影响返回,输出0
再看看f2,执行return i,由于是显示命名的返回值,不会创建临时变量,也不需要再赋值;然后执行defer中的i++,最后返回i,因为返回的i,所以defer中对i的修改是会影响到返回的,输出1
同理,如果返回的是指针类型*int,即时f1返回的是临时变量,因为指针执行的是同一块内存,所以取出的值是
defer中修改过的
func f1() *int {
i := 0
defer func(){
i++
}()
return &i
}
func main() {
r := f1()
fmt.Println(*r)
}
// 输出1