普通defer与延迟匿名函数的变量捕获差异疑问
Go中defer普通调用与匿名函数的差异解析
先看你给出的代码:
func main() { x := "hello" defer fmt.Println(x) x = "world" defer func() { fmt.Println(x) }() defer fmt.Println(x) x = "qwerty" }
你推测的输出是对的,实际运行结果就是:
world qwerty hello
核心差异在于参数/变量的求值时机:
普通defer调用(比如
defer fmt.Println(x)):
当defer语句执行的那一刻,Go会立即对该函数的所有参数进行求值,把求值后的结果和函数本身一起存入defer栈。后续无论变量怎么修改,都不会影响已经存在栈里的参数值。比如第一个defer执行时x是"hello",这个值就被固定下来了;第三个defer执行时x是"world",同样这个值也被固定,后面x改成"qwerty"和它无关。defer绑定匿名函数(比如
defer func() { fmt.Println(x) }()):
defer语句执行时,只是把匿名函数的引用存入栈,函数内部用到的变量x并没有提前求值。只有当这个匿名函数真正执行(main函数结束后按顺序执行defer时),才会去读取x的当前值——也就是变量最后被修改后的结果,所以它输出的是"qwerty"。
defer的LIFO(后进先出)执行顺序只是决定了这些defer的执行先后,而变量值的差异完全来自于上述的求值时机不同。
内容的提问来源于stack exchange,提问作者neo
相关产品推荐
相关产品推荐

