
Go 的 for 循环每次迭代不创建新的词法作用域,但显式声明的变量(如 idx := i)在每次迭代中都会重新声明并绑定新值;若直接捕获循环变量 i,所有闭包将共享同一变量实例,导致意外输出。
go 的 `for` 循环每次迭代不创建新的词法作用域,但显式声明的变量(如 `idx := i`)在每次迭代中都会重新声明并绑定新值;若直接捕获循环变量 `i`,所有闭包将共享同一变量实例,导致意外输出。
在 Go 中,for 循环本身不引入嵌套作用域。根据 Go 语言规范关于 for 语句的定义:
"Each 'if', 'for', and 'switch' statement is considered to be in its own implicit block."
"A 'for' statement specifies repeated execution of a block."
关键在于:这个“implicit block”仅对控制结构自身生效,不为每次迭代创建独立作用域。也就是说:
- 循环变量 i(如 for i := 0; ...)在整个循环生命周期内是同一个变量,其内存地址不变,每次迭代只是更新其值;
- 而在循环体内使用 := 声明的变量(如 idx := i)属于该次迭代的语句块作用域,但由于 Go 不为每次迭代新建作用域,此处的 idx 实际上是每次迭代重新声明的新变量(编译器保证其独立性),等价于在每次迭代中隐式创建一个独立绑定。
因此,以下代码正确输出 0 1 2:
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
var funcs []func() for i := 0; i <p>而若直接捕获 i,则所有闭包共享同一个变量:</p><pre class="brush:php;toolbar:false;">var funcs []func() for i := 0; i <p>⚠️ 注意事项:</p>
- Go 1.22+ 已在 for range 语句中默认为每次迭代创建独立变量(见 Go Proposal #55589),但传统 for init; cond; post 形式仍保持原有语义;
- 为确保行为可预测,始终显式复制循环变量(如 v := v)是最佳实践;
- 不要依赖作用域“自动隔离”,而应通过变量声明时机和闭包捕获逻辑主动管理状态。
总结:Go 的 for 迭代不终结前一次的作用域(因本就无迭代级作用域),但编译器会为 := 声明的变量提供每次迭代的独立绑定——这是语言实现保障的行为,而非作用域规则所致。理解这一点,是写出可靠闭包逻辑的关键。










