我们都知道,defer
往往在函数的最后执行,遵循先进后出 原则,在return
函数写入返回值后执行,而且传入的形参会立即读入,后续修改对其无影响
Go 函数返回过程完整流程
当一个函数执行到 return
语句时,执行顺序是:
- 计算
return
后的表达式(如果有的话),将结果赋值给返回值; - 执行所有的 defer 语句(按照后进先出 LIFO 的顺序);
- 函数真正返回(携带返回值) 。
下面来看这三个案例
go
package main
import "fmt"
func Func1() int {
a := 0
defer func() {
a++
}()
return a
}
func Func2() (a int) {
a = 0
defer func() {
a++
}()
return
}
func Func3() *int {
a := new(int)
*a = 0
defer func() {
*a++
}()
return a
}
func main() {
fmt.Println(Func1())
fmt.Println(Func2())
fmt.Println(*Func3())
}
输出结果为
0 1 1
案例分析
这三个究竟有什么区别呢?
案例一:
- 首先,我们获得a的值0,然后会重新赋值一份给临时的返回槽(slot)当中
- 然后,调用defer,修改局部变量a为1,但是a已被copy一份到返回槽,所以重新赋值没有用
- 返回0
案例二:
- 首先,我们获得a的值0,然后会重新赋值一份给临时的返回槽(slot)当中
- 然后defer修改了引用类型a的值
- 返回1
案例三:
与案例一相似,但是传递的是指针,能修改地址中存储的值,所以返回的是1