defer 匿名返回值&命名返回值

defer 匿名返回值&命名返回值

1.问题的提出

关于 Go defer 对匿名返回值和命名返回值的不同行为

func test1() int {
	var a int

	defer func() {
		a++
	}()

	return a
}

func test2() (a int) {
	defer func() {
		a++
	}()

	return a
}

test1 最终返回 0,test2 最终返回 1

参考:

Golang中defer、return、返回值之间执行顺序的坑

推迟,恐慌和恢复

2.问题解决

​ 先来假设出结论(这是正确结论),帮助大家理解原因:

  1. 多个defer的执行顺序为“后进先出”;
  2. 所有函数在执行RET返回指令之前,都会先检查是否存在defer语句,若存在则先逆序调用defer语句进行收尾工作再退出返回;
  3. 匿名返回值是在return执行时被声明,有名返回值则是在函数声明的同时被声明,因此在defer语句中只能访问有名返回值,而不能直接访问匿名返回值;
  4. 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
}


posted @ 2021-01-13 00:38  细雨骑驴入剑门  阅读(411)  评论(0编辑  收藏  举报