func ForRangeValue_1() {
var mapAges map[string]int
mapAges = make(map[string]int)
mapAges["name-1"] = 1
mapAges["name-2"] = 2
mapAges["name-3"] = 3
var newAges map[string]*int
newAges = make(map[string]*int)
for k, v := range mapAges {
newAges[k] = &v;
}
for k, v := range newAges {
fmt.Println(k, v, *v)
}
}
咋看,很想newAges从mapAges拷贝了一份key,value的值,其实不是,运行结果如下:
=== RUN TestForRangeValue_1
name-1 0xc0000542f0 3
name-2 0xc0000542f0 3
name-3 0xc0000542f0 3
--- PASS: TestForRangeValue_1 (0.00s)
PASS
从结果可以看出newAges的value部分,是个地址值,并且指向了同一地址。按照其他语言,for k,v应该是临时变量,每遍历一次,都会导致产生新的临时变量k,v。但golang没有,下面我们简单验证一下:
func ForRangeValue_2() {
var mapAges map[string]int
mapAges = make(map[string]int)
mapAges["name-1"] = 1
mapAges["name-2"] = 2
mapAges["name-3"] = 3
for k, v := range mapAges {
fmt.Println(&k, &v, k, v)
}
}
=== RUN TestForRangeValue_2
0xc000048550 0xc0000542f0 name-1 1
0xc000048550 0xc0000542f0 name-2 2
0xc000048550 0xc0000542f0 name-3 3
--- PASS: TestForRangeValue_2 (0.00s)
PASS
可以看到,for k,v中每一次遍历中,k和v都指向了一个相同地址,然后每次将map的key和value按照值传递的原则,赋值给k,v。
golang这样做,有他的道理,毕竟带来一定的性能提升。
解决方案:
竟然golang编译器没给我们创建新的变量,那么我们只好自己来生成
func ForRangeValue_3() {
var mapAges map[string]int
mapAges = make(map[string]int)
mapAges["name-1"] = 1
mapAges["name-2"] = 2
mapAges["name-3"] = 3
var newAges map[string]*int
newAges = make(map[string]*int)
for k, v := range mapAges {
var pv int = v
newAges[k] = &pv
}
for k, v := range newAges {
fmt.Println(k, v, *v)
}
}
=== RUN TestForRangeValue_3
name-1 0xc0000542f0 1
name-2 0xc0000542f8 2
name-3 0xc000054300 3
--- PASS: TestForRangeValue_3 (0.00s)
PASS