You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言defer行为差异面试题:两段代码输出不同的原因解析

Go中Defer在不同返回值声明下的行为差异解析

咱们先看两段看似相似但输出截然不同的Go代码:

第一段代码(输出1)

func test() int {
    var x int
    defer func() { x++ }()
    x = 1
    return x
}
func main() {
    fmt.Println(test())
}

输出结果:1

第二段代码(输出2)

func test() (x int) {
    defer func() { x++ }()
    x = 1
    return
}
func main() {
    fmt.Println(test())
}

输出结果:2

核心差异:返回值的声明方式

这两段代码的本质区别在于返回值是匿名还是命名,结合反汇编我们能更清晰看到底层逻辑:

第一段代码的反汇编逻辑分析

在第一段的test函数里,x是函数内部的普通局部变量。当执行return x时,Go会先把x的当前值(也就是1)拷贝到函数的返回值栈帧位置,之后才会执行defer函数。而defer里的x++修改的是函数内部的那个局部变量x,和已经拷贝到返回位置的值没有关联,所以最终返回的是之前拷贝好的1。

从反汇编指令也能验证这一点:return x对应的操作会完成值的拷贝,后续defer的操作只影响栈上的局部变量,不会触碰到已经准备好的返回值。

第二段代码的反汇编逻辑分析

第二段的test函数用了命名返回值((x int)这种声明方式)。这时候,x从一开始就不是普通局部变量——它就是函数返回值对应的栈内存变量。当执行return时,Go不需要做值拷贝,因为返回值变量本身就是x。之后执行defer函数里的x++,直接修改的就是这个返回值变量,所以最终返回的是修改后的2。

反汇编里能看到,这段代码的return指令没有额外的拷贝操作,defer的操作直接作用于返回值对应的内存位置,自然会改变最终的返回结果。

总结一下

  • 匿名返回值:return时会把局部变量的值拷贝到返回栈帧,defer修改的是局部变量,不影响最终返回值
  • 命名返回值:return时直接使用命名变量作为返回值,defer修改这个变量会直接改变返回结果

内容的提问来源于stack exchange,提问作者frankegoesdown

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:10:21