代码如下:
package main
import (
"fmt"
"time"
)
type Int struct {
int int
}
func multi(i *Int) {
i.int = i.int*100
}
func main() {
a := []Int {
{1},
{2},
{3},
{4},
}
for _, v := range a{
multi(&v)
go func() {
ticker := time.NewTicker(time.Second)
<- ticker.C
fmt.Println(v)
}()
}
time.Sleep(time.Second*5)
fmt.Println(a)
}
理想输出结果应该为:
{100}
{200}
{300}
{400}
{{100} {200} {300} {400}}
实际输出为:
{400}
{400}
{400}
{400}
{{1} {2} {3} {4}}
问题一:为何v值一样?
答:在每个循环中开启的新goroutine时有停顿一秒,循环已经结束,所有的goroutine里面的v值是指向同一个地址的值,即最后一次循环的v值。
问题二:为何数组值没有改变?
在回答二问题的时候,我还需要列上一组代码与结果,如下:
package main
import (
"fmt"
)
type Int struct {
int int
}
func multi(i *Int) {
i.int = i.int*100
}
func main() {
a := []Int {
{1},
{2},
{3},
{4},
}
var b = make([]*Int, len(a))
for i, v := range a{
multi(&v)
b[i] = &v
}
fmt.Println(a)
fmt.Println(b[0],b[1],b[2],b[3])
}
结果:
[{1} {2} {3} {4}]
&{400} &{400} &{400} &{400}
答:在Golang的range方法中,始终使用值拷贝的方式代替被遍历的元素本身,简单来说,就是for…range
中那个value
,是一个值拷贝,而不是元素本身。这样一来,当我们期望用&获取元素的指针地址时,实际上只是取到了value
这个临时变量的指针地址,而非list
中真正被遍历到的某个元素的指针地址。因此上诉结果也就得到了完美的解释。
可再看下例补充:
package main
import "fmt"
func main() {
a := []int {1,2,3,4}
for i, v := range a{
fmt.Println(&v,&a[i])
}
}
结果:
0xc000016078 0xc000018100
0xc000016078 0xc000018108
0xc000016078 0xc000018110
0xc000016078 0xc000018118
所以,range的坑搞懂了。嘿嘿