示例代码
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("golang version:", runtime.Version())
for i := 0; i < 10; i++ {
fmt.Println(&i)
}
}
代码说明
这个代码先打印了使用的golang的版本,然后进行一个for循环,for循环中打印了变量i的地址
执行go run xxx.go
看下结果
golang 1.21的运行结果
go run demo/basic_for.go
golang version: go1.21.5
0xc0000120d8
0xc0000120d8
0xc0000120d8
0xc0000120d8
0xc0000120d8
0xc0000120d8
0xc0000120d8
0xc0000120d8
0xc0000120d8
0xc0000120d8
可以看到在1.21.5这个版本中,打印出来的地址都是一样的,在1.22中又会如何呢
golang 1.22的运行结果
go run demo/basic_for.go
golang version: go1.22.1
0xc0000a6020
0xc0000a6028
0xc0000a6030
0xc0000a6038
0xc0000a6040
0xc0000a6048
0xc0000a6050
0xc0000a6058
0xc0000a6060
0xc0000a6068
可以看到在1.22.1的这个版本中,打印出来的地址都是不一样的。
再举个例子
package main
import (
"fmt"
)
func main() {
var ids []*int
for i := 0; i < 10; i++ {
ids = append(ids, &i)
}
for _, v := range ids {
fmt.Println("demo i value:", *v)
}
}
在1.21的版本中的结果:
golang version: go1.21.5
demo i value:10,demo i value:10,demo i value:10,demo i value:10,demo i value:10,demo i value:10,demo i value:10,demo i value:10,demo i value:10,demo i value:10,
可以看到ids这个slice中的值都是10
在1.22的版本中的结果
`golang version: go1.22.1
demo i value:0,demo i value:1,demo i value:2,demo i value:3,demo i value:4,demo i value:5,demo i value:6,demo i value:7,demo i value:8,demo i value:9,
上述的1.21存在问题的代码有比较简单的解决办法就是在循环中加上一行代码i:=i
就可以解决问题。
出现上述问题的原因是1.22 loopvar的规则变了,1.22之前的版本中for循环中的变量只会循环一次,不论需要循环多少次都只初始化一次,但是1.22中变成了每次循环都会创建新变量,以避免意外共享bug。
golang的release note是这么描述的Previously, the variables declared by a “for” loop were created once and updated by each iteration. In Go 1.22, each iteration of the loop creates new variables, to avoid accidental sharing bugs.