defer是否在函数返回后执行?一段Go语言代码返回值不符合预期的原因排查
为什么Go代码的输出和预期不符?
嘿,这个问题其实戳中了Go语言里return和defer的执行细节,我来给你一步步理清楚:
1. 为什么会打印出0?
你遇到的核心问题是Go的return语句不是原子操作,它的执行分为三个关键步骤:
- 第一步:先计算要返回的具体值,把这个值存入一个专门的临时返回变量里;
- 第二步:执行当前函数中所有已声明的
defer语句; - 第三步:把临时返回变量的值作为函数最终返回值返回。
放到你的代码里看:
- 当
example()执行到return i时,先读取了全局变量i的当前值(初始是0),并把这个0存进了临时返回变量; - 随后才执行defer的匿名函数:虽然它把全局变量
i改成了1,但这个修改不会影响已经提前存好的临时返回变量; - 所以
example()最终返回的是临时变量里的0,main中第一个fmt.Println自然就输出0了。
2. defer是在函数返回后执行吗?
绝对不是,defer的执行时机是函数真正返回之前——也就是在return的“计算返回值”步骤之后,“返回结果”步骤之前。
我们把你的代码完整走一遍流程,就能看得更清楚:
- 全局变量
i默认初始化为0; main函数调用example():- 先执行
fmt.Println("first"),输出first; - 执行
return i:计算得到i=0,存入临时返回变量; - 执行defer匿名函数:输出
defer,并把全局变量i改成1; example()返回临时变量的0,main中第一个fmt.Println输出0;
- 先执行
main执行第二个fmt.Println(i),此时全局变量i已经被defer修改为1,所以输出1。
如果你想让example()返回1,可以改成返回指针类型,这样defer中修改原变量就能影响返回值:
package main import ( "fmt" ) var i int func example() *int { defer func() { fmt.Println("defer") i = 1 }() fmt.Println("first") return &i } func main() { fmt.Println(*example()) fmt.Println(i) }
这段代码的输出就会和你最初的预期一致。
内容的提问来源于stack exchange,提问作者Vitor Falcão
相关产品推荐
相关产品推荐

