golang内幕之for-range-value

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

 

 


版权声明:本文为QQ1130141391原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。