2016-11-21 40 views
0
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 

有人能解释为什么结果是一样的以上?

+3

您不断添加相同的指针'v'到切片。另请参见https://golang.org/doc/faq#closures_and_goroutines – JimB

+0

如果您需要指针,则需要将映射的值设置为像“* int”这样的指针类型。地图项目可以在内存中移动,因此您无法直接在地图中获取指针。 [这是一个稍微扩展的版本。](http://stackoverflow.com/a/32751792/2714852) – twotwotwo

回答

2

this doc引用:

[...]的循环的每次迭代使用变量v的同一实例,因此每个闭合股该单个可变[...]

换句话说,循环变量v在所有迭代中都被重复使用,因此您可以为所有切片元素分配相同的指针。

变量声明循环不会被回收这样的,所以这将作为你所期望的:

for _, v := range m { 
    vv := v 
    array[i] = &vv 
    fmt.Printf("Add to array: %d\n", v) 
    i++ 
} 

顺便说一句,你有没有解释为什么要使用*int作为值的类型。如果只使用int值,所有这些都会更简单。

+0

我不确定什么是OP期望值在这里,但这样做现在阵列和地图内的指针现在将尊重不同的地方。 –

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) 
    } 
} 

游乐场链接:https://play.golang.org/p/TpkXlCElLx