go中for循环的迭代变量必须在for语句内声明,不可提前在外层声明后复用,如禁止var i int; for i = 0; i
Go里for循环的迭代变量只能在for语句中声明
Go不允许在
for外提前声明迭代变量再用于循环控制——比如不能像var i int; for i = 0; i 这样写(语法错误)。所有经典C风格的<code>for init; cond; post形式,init部分必须是短变量声明:=或var语句,且仅作用于该for作用域。三种常见for写法及变量作用域差异
实际编码中容易混淆的是变量是否“复用”或“逃逸”。关键看声明位置和方式:
for i := 0; i :每次迭代<code>i都是同一个变量(地址不变),值被原地更新;闭包捕获时会出问题for _, v := range slice:每次迭代的v是新变量(Go 1.21+默认行为),但老版本中v是复用的,需v := v显式复制才能安全闭包for i := range slice:i始终复用,行为稳定,无版本差异闭包里用迭代变量必须显式拷贝
这是最常踩的坑。下面代码会输出5个
5,而不是0 1 2 3 4:<pre class="brush:php;toolbar:false;">for i := 0; i <p>修复方法只有两种:</p>
- 把
i作为参数传入匿名函数:<code>func(i int) { fmt.Println(i) }(i)- 在循环体内重新声明:
ii := i; go func() { fmt.Println(ii) }()range遍历时v到底是不是新变量?看Go版本和编译器优化
Go 1.21起,
for _, v := range s中的v默认每次迭代都分配新变量(除非确定不会逃逸)。但如果你用的是1.20或更早版本,v始终复用——这意味着:
- 直接取
&v地址,所有迭代拿到的是同一块内存- 存入切片或传给goroutine前,必须
v := v强制拷贝- 用
go vet能检测到这类潜在错误,建议开启最稳妥的做法,是只要涉及地址、闭包、并发,就别依赖“v是否新建”,统一加一次赋值。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!












