2016-09-20 94 views
2

这里是我的代码:为什么一个函数中的映射值受到另一个函数中映射项的影响?

func test(v map[string]string) { 
    v["foo"] = "bar" 
} 

func main() { 
    v := make(map[string]string) 
    test(v) 
    fmt.Printf("%v\n", v) // prints map[foo:bar] 
} 

我很新去的,但据我所知,因为我通过地图的价值test(),而不是一个指针图,test()功能应该修改地图的一个不同的变量,从而不会影响main()中变量的值。我本来期望它打印map[]。我测试了一个不同的场景:

type myStruct struct { 
    foo int 
} 

func test2(v myStruct) { 
    v.foo = 5 
} 

func main() { 
    v := myStruct{1} 
    test2(v) 
    fmt.Printf("%v\n", v) // prints {1} 
} 

在这种情况下,代码的行为与我的预期相同。 main()函数中的v变量不受test2()中变量的更改影响。那么为什么地图不同呢?

回答

4

你是对的,当你将某些东西传递给一个函数时,会进行复制。但是地图是某种底层数据结构的描述符。所以当你传递一个map值到一个函数时,只有描述符会被复制,它将表示/指向存储地图数据(条目)的相同数据结构。

这意味着如果该函数对地图的条目(添加,删除,修改条目)进行任何修改,这是从调用者观察到的。

阅读The Go Blog: Go maps in action了解详情。请注意,sliceschannels也是如此;一般来说可以使用内置的make()函数创建的类型。这就是为什么zero value这些类型是nil,因为这些类型的值需要一些额外的初始化,这是在调用make()时完成的。

在另一个示例中,您使用的值是struct,它们不是描述符。当你将一个struct值传递给另一个函数时,它会创建一个结构值的完整副本(复制其所有字段的值),当在函数中进行修改时,它将不会对原始结果产生任何影响,因为副本将被修改 - 这是不同的。