defer 匿名返回值&命名返回值
defer 匿名返回值&命名返回值
1.问题的提出
func test1() int {
var a int
defer func() {
a++
}()
return a
}
func test2() (a int) {
defer func() {
a++
}()
return a
}
test1 最终返回 0
,test2 最终返回 1
。
参考:
2.问题解决
先来假设出结论(这是正确结论),帮助大家理解原因:
- 多个defer的执行顺序为“后进先出”;
- 所有函数在执行RET返回指令之前,都会先检查是否存在defer语句,若存在则先逆序调用defer语句进行收尾工作再退出返回;
- 匿名返回值是在return执行时被声明,有名返回值则是在函数声明的同时被声明,因此在defer语句中只能访问有名返回值,而不能直接访问匿名返回值;
- return其实应该包含前后两个步骤:第一步是给返回值赋值(若为有名返回值则直接赋值,若为匿名返回值则先声明再赋值);第二步是调用RET返回指令并传入返回值,而RET则会检查defer是否存在,若存在就先逆序插播defer语句,最后RET携带返回值退出函数;
因此,defer、return、返回值三者的执行顺序应该是:return最先给返回值赋值;接着defer开始执行一些收尾工作;最后RET指令携带返回值退出函数。
3.注册顺序
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}