需要说明 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 单元测试