

新闻资讯
技术学院在 go 中,for 循环内的匿名函数若引用循环变量,会因所有闭包共享同一变量实例而导致意外输出(如全部打印最后一次迭代的值);正确做法是在每次迭代中显式创建新变量副本,使每个闭包绑定独立值。
这是一个在 Go 初学者和中级开发者中高频出现的经典陷阱:循环变量被闭包意外共享。
在原始代码中:
for _, s := range [...]string{"goodbye", "cruel", "world"} {
functions = append(functions, func() {
log.Println(s) // ❌ 所有函数都引用同一个变量 s
})
}尽管看起来 s 在每次迭代中“更新”,但 Go 的 for 循环复用同一个栈变量地址——即 s 始终是同一内存位置。因此,所有匿名函数捕获的并非某次迭代的值,而是对这个可变地址的引用。当循环结束时,s 的最终值为 "world",所有闭包执行时自然都输出 "world"。
✅ 正确解法:在循环体内通过短变量声明 s := s 显式创建新变量,触发编译器为其分配独立内存空间:
package main
import "log"
var functions []func()
func main() {
for _, s := range [...]string{"goodbye", "cruel", "world"} {
s := s // ✅ 创建当前迭代值的独立副本
functions = append(functions, func() {
log.Println(s) // 现在每个闭包绑定各自的 s
})
}
for _, f := range functions {
f()
}
}运行后将按预期输出:
2009/11/10 23:00:00 goodbye 2009/11/10 23:00:00 cruel 2009/11/10 23:00:00 world
⚠️ 注意事项:
总结:闭包捕获的是变量 本身,而非其某次迭代的 值。理解这一点,并养成在循环中对需捕获的变量做一次显式重声明的习惯,是写出可靠 Go 闭包代码的关键。