2016-09-20 48 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值傳遞給另一個函數時,它會創建一個結構值的完整副本(複製其所有字段的值),當在函數中進行修改時,它將不會對原始結果產生任何影響,因爲副本將被修改 - 這是不同的。