func TestMapValuePointer2(t *testing.T) {
fmt.Println("Test Map Value Pointer 2")
m := map[string]int{"rsc": 3711, "r": 2138, "gri": 1908, "adg": 912}
n := len(m)
array := make([]*int, n)
i := 0
for _, v := range m {
array[i] = &v
fmt.Printf("Add to array: %d\n", v)
i++
}
for _, k := range array {
fmt.Printf("Value: %d\n", *k)
}
}
输出不是:
Value: 912 Value: 3711 Value: 2138 Value: 1908
相反,输出可能如下:
Value: 912 Value: 912 Value: 912 Value: 912
有人可以解释为什么结果如上所述吗?
答案 0 :(得分:2)
引自this doc:
[...]循环的每次迭代使用变量v的相同实例,因此每个闭包共享该单个变量[...]
换句话说,循环变量// A C implementation of memcpy()
#include<stdio.h>
#include<string.h>
void myMemCpy(void *dest, void *src, size_t n)
{
// Typecast src and dest addresses to (char *)
char *csrc = (char *)src;
char *cdest = (char *)dest;
// Copy contents of src[] to dest[]
for (int i=0; i<n; i++)
cdest[i] = csrc[i];
}
在所有迭代中都会被重用,因此您可以为所有切片元素指定相同的指针。
在循环中声明循环的变量不会像那样被回收,所以这将按预期工作:
v
顺便说一句,您还没有解释为什么要使用for _, v := range m {
vv := v
array[i] = &vv
fmt.Printf("Add to array: %d\n", v)
i++
}
作为值的类型。如果您只使用*int
值,那么所有这些都会更简单。
答案 1 :(得分:1)
这里的问题是在循环期间创建的变量v
实际上是我们在地图中具有的值的副本。与v
相关的内存在循环开始时分配一次,稍后重新用于其他值,因为此处指的最后一个值是912,在这种情况下,您在数组中看到912。
一个简单的证明就是:https://play.golang.org/p/K0yAbEIf3G
对此的一个解决方法是将地图值更改为* int指针而不是值,稍后我们可以取消引用它们以获取实际值:
package main
import "fmt"
func main() {
fmt.Println("Test Map Value Pointer 2")
a, b, c, d := 3711, 2138, 1908, 912
m := map[string]*int{"rsc": &a, "r": &b, "gri": &c, "adg": &d}
n := len(m)
array := make([]*int, n)
i := 0
for _, v := range m {
array[i] = v
fmt.Printf("Add to array: %d\n", *v)
i++
}
for _, k := range array {
fmt.Printf("Value: %d\n", *k)
}
}