需要说明 2 点
1. return 的执行包含两步:
第一步给返回值赋值,匿名返回值先在此声明再赋值,而有名返回值是函数声明时声明的,在此直接赋值;
第二步调用 RET 返回指令并传入返回值,在执行 RET 返回指令时会先检查是否存在 defer 语句 ,若存在则按“先进后出”依次执行,再将返回值带出退出函数
2. defer 声明时会先确定参数的值,defer 推迟执行的仅是其函数体
package main import ( "fmt" ) func testA() int { fmt.Println("-------------------testA") var i int defer func() { i++ fmt.Println("A#1", i) }() defer func() { i++ fmt.Println("A#2", i) }() fmt.Println("A#3", i) // 第一步:匿名返回值先声明再赋值,声明匿名返回值后将 i 值传递给匿名返回值 // 第二步:检查是否存在 defer 语句,存在则逆序执行,虽然 defer 里修改了 i 的值,但由于为匿名返回值的值是通过 i 值传递获得的,故 i 的值修改不会影响匿名返回值的值 return i } func testB() *int { fmt.Println("-------------------testB") i := 2 // defer 声明时会先确定参数的值,defer 推迟执行的仅是其函数体 // 故此处声明时会有 j = 2, k = 0 defer func(j, k int) { i++ fmt.Println("B#1", i, &i) fmt.Println("B#2", j) fmt.Println("testA", k) }(i, testA()) fmt.Println("B#5", i, &i) // 第一步:匿名返回值先声明再赋值,声明匿名返回值后将 i 地址传递给匿名返回值 // 第二步:检查是否存在 defer 语句,存在则逆序执行,defer 里修改了 i 的值,由于匿名返回值的地址指向 i 的地址,故匿名返回值的值同 i 的值一致 return &i } func testC() (i int) { fmt.Println("-------------------testC") defer func() { i++ fmt.Println("C#1", i, &i) }() i = 5 fmt.Println("C#2", i, &i) // 第一步:有名返回值则直接赋值,此处的返回值在函数声明时已然声明为 i // 第二步:检查是否存在 defer 语句,存在则逆序执行,defer 里修改了 i 的值,也即返回值 return 8 } func main() { defer func() { fmt.Println("D#1") if err := recover(); err != nil { fmt.Println(err) } }() ptr := testB() fmt.Println("testB", *ptr, ptr) fmt.Println("testC", testC()) panic("D#2") }
运行结果为
-------------------testB -------------------testA A#3 0 A#2 1 A#1 2 B#5 2 0xc00001e0a8 B#1 3 0xc00001e0a8 B#2 2 testA 0 testB 3 0xc00001e0a8 -------------------testC C#2 5 0xc00001e0f0 C#1 9 0xc00001e0f0 testC 9 D#1 D#2
本文标题:golang 中的 defer 与 return
版权声明:本文使用「署名 4.0 国际」创作共享协议,转载或使用请遵守署名协议。
相关文章
上一篇:golang 单元测试