发布于2026-07-18 阅读(0)
扫一扫,手机访问
先来分享一个很多人踩过的坑:很多人以为defer是“函数返回后才执行”,但实际上它的执行时机更微妙——是在函数控制流离开当前栈帧之前。这个时间点,比你想象得要更靠后,搞清楚它对写出靠谱的Go代码至关重要。
这个是初学者最容易掉进去的陷阱之一。举个例子:
func example() { x := 10 defer fmt.Println("x =", x) // 此处 x 被拷贝为 10 x = 20 return}
输出一定是 x = 10,不是 20。原因很简单:defer 后面表达式中所有参数,在执行到该 defer 语句那一行时就已经完成计算并保存了。这个规则的影响面还挺广的:
int、string、struct)会被完整拷贝*int、[]byte、map、chan)拷贝的是地址,后续修改会影响 defer 中读到的内容func() { ... } 形式不带参数,则访问的是变量最新值;但若显式传参如 func(n int) { ... }(x),则仍是注册时的值不是按代码顺序,而是“最后声明的最先执行”。这个顺序决定了资源释放是否合理:
func openAndClose() { f1, _ := os.Open("a.txt") defer f1.Close() f2, _ := os.Open("b.txt") defer f2.Close() // 实际执行顺序:f2.Close() → f1.Close()}
defer f(i) 会全部注册同一份 i 的最终值,应改用 defer func(n int) { f(n) }(i)这个“之间”阶段很微妙:返回值已写入栈帧,但函数还没退出。所以命名返回值可被 defer 修改:
func counter() (ret int) { ret = 1 defer func() { ret += 10 }() // 这里能改 ret return // 返回值 ret=1 已确定,但 defer 还没跑;defer 跑完才真正返回}
输出是 11。需要留意的是:
return 1 这种匿名形式无法被 defer 修改早期版本 defer 有明显栈分配和链表操作成本,但现在情况已大为改观:
真正要警惕的不是性能,而是逻辑错位:比如在 defer 里调用可能 panic 的函数,又没 recover,会导致 panic 被延迟传播,堆栈信息指向错误位置。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8