跳转至

Go Range的奇怪机制

在Go1.22.0中已经得到修正,如果go.mod声明为1.22.x版本,会自动使用新的语义

在下面的代码中,请问输出是什么?

l := []int{1, 2, 3}  
for _, v := range l {
    fmt.Printf("%d, %p", v, &v)
}

答案是:

1 某个地址A
2 A
3 A
你可能觉得很奇怪,为什么通过range得到的v值不一样,但是地址一样呢?

假设Go是一家漫画店的老板,最近有个3页的漫画,你想去看。Go老板拿出一台pad,上面一次只能显示一页漫画。于是,你通过同一个pad读取了三页不同的漫画。

这就是range的设计方式,Go认为你通过range是想读一个变量,而不是得到变量本身。于是,在遍历一个元素var A []T的时候Go会开辟一个类型T的一块空间,每次遍历,就从A的对应位置读值,赋给开辟的空间。也就是说,每次遍历都是在同一个内存地址读副本。

那么如果是想进行如列表元素append之类的操作怎么办呢?在for的下面加一行就好:

v := v