這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
http://wangzhezhe.github.io/blog/2016/01/22/golangmapaddressability-dot-md/
在golang中關於map可達性的問題(addresable?)
在go playground中有這樣的例子:
12345678910111213141516 |
package mainimport ( "fmt")type Type struct { A string}func main() { items := make(map[string]Type) items["q"] = Type{} items["q"].A = "abc" fmt.Println(items)}
|
這樣在執行的時候會報一個常見的錯誤:cannot assign to items["q"].A
改變一下value的聲明方式,之後再進行類似的操作就可以了:
12345678910111213141516 |
package mainimport ( "fmt")type Type struct { A string}func main() { items := make(map[string]*Type) items["q"] = &Type{} items["q"].A = "abc" fmt.Printf("%+v", items)}
|
在golang設計的時候,map中的value值應該是地址不可達的,就是說直接取map中的元素的地址會報錯,比如把上面例子中的main函數改成下邊這樣:
1234 |
itemsb := make(map[string]Type)itemsb["p"] = Type{3}pointer := &itemsb["p"]fmt.Println(pointer)
|
會報出cannot take the address of itemsb["p"]的錯誤。原因大致是因為,在golang中,一個容量不斷增長的map可能會導致原來map中的一些元素髮生rehashing,使得他們被重新分配到新的storage location上,這樣可能會導致原先得到的address變得不可用。就是所謂的map member 的 not addresable。
正如這個答案中寫的,map的indexing操作本來就是地址不可達的,這和golang中map的具體實現機制有關,golang中的map並沒有保證它們的value值的地址是不可變的,因為value值的地址很有可能被重新分配,就像前面所說的那樣。一個修改的辦法就是把value值設定成為指標的形式,這樣就相當於添加了一個額外的entry,即使真正需要的那個值的位置發生了變化,也可以redirection過去。以後使用map聲明一個結構體的value值的時候,這一點要特別注意下。
對於slice的index操作就是地址可達的,對於map則是不可達的,總是使用map的時候要特別注意下。
??map is a reference to the map contents, but it does not hold references (unless it explicitly stores pointers).
相關參考:
https://golang.org/ref/spec#Address_operators
https://code.google.com/p/go/issues/detail?id=3117
https://groups.google.com/forum/#!topic/golang-nuts/4_pabWnsMp0
https://golang.org/ref/spec
http://stackoverflow.com/questions/13101298/calling-a-pointer-method-on-a-struct-in-a-map https://golang.org/ref/spec#Address_operators
http://stackoverflow.com/questions/16059038/can-not-assign-to-a-struct-member-from-map
首先要明確一下,在聲明的時候&Type{}與Type{}的區別在哪裡
currently map member並非是addressable的。