这与为什么为什么不接受(&)映射成员的地址而允许(&)slice元素相同?但我对接受的答案不满意:“切片由后备数组支持,而映射则不支持。”
注意:现在,我已对上面提到的问题添加了自己的答案。
Map中的Access Struct问题(不带复制)甚至更好,但是它被接受的答案是您不能修改map中的struct值字段,因为您无法获取其地址(这是我的问题)。
就像切片一样,映射由内存结构(可能包括数组)支持。
那么,为什么我不能使用映射值的地址的真正原因是什么?
我想就地修改地图结构值。可以使用++或+ =等运算符在适当的位置修改地图中的数值
func icandothis() { cmap := make(map[int]complex64) cmap[1] += complex(1, 0) fmt.Println(cmap[1]) }
但是结构值不能修改:
type Complex struct { R float32 I float32 } func (x *Complex) Add(c Complex) { x.R += c.R x.I += c.I } func but_i_cannot_do_this() { cmap := make(map[int]Complex) //cmap[1].Add(Complex{1, 0}) fmt.Println(cmap[1]) } func so_i_have_to_do_this() { cmap := make(map[int]Complex) c := cmap[1] c.Add(Complex{1, 0}) cmap[1] = c fmt.Println(cmap[1]) }
让我们从这个虚假的声明开始:
我想就地修改地图结构值。可以使用++或+ =等运算符在适当的位置修改地图中的数值 func icandothis() { cmap := make(map[int]complex64) cmap[1] += complex(1, 0) fmt.Println(cmap[1]) }
让我们扩展简写形式:
package main import ( "fmt" ) func icandothisShort() { cmap := make(map[int]complex64) cmap[1] += complex(1, 0) fmt.Println(cmap[1]) } func icandothisLong() { cmap := make(map[int]complex64) // An assignment operation x op= y where op is a binary arithmetic operator // is equivalent to x = x op (y) but evaluates x only once. // cmap[1] += complex(1, 0) v := cmap[1] // v = zero value = complex(0, 0) v = v + complex(1, 0) // v = complex(0, 0) + complex(1, 0) = complex(1, 0) cmap[1] = v // cmap[1] = v = complex(1, 0) a := cmap[1] // a = complex(1, 0) fmt.Println(a) // complex(1, 0) } func main() { icandothisShort() icandothisLong() }
游乐场:https://play.golang.org/p/1OgmI_AD9uN
输出:
(1+0i) (1+0i)
您可以在中看到icandothisLong()的扩展形式icandothisShort(),没有就地更新。
icandothisLong()
icandothisShort()
下一个虚假声明,
就像切片一样,映射由内存结构(可能包括数组)支持。 那么,为什么我不能使用映射值的地址的真正原因是什么?
真正的原因是您不了解地图数据结构。
存储桶存储结构支持地图。映射键通过不完美的动态哈希标识当前的主存储桶。映射键和值存储在主存储桶或溢出存储桶中。随着创建,更新和删除地图条目,地图存储区会不断进行重组。地图条目在内存中没有固定的位置。
做一些基础研究。例如,
GopherCon 2016:Keith Randall-地图实施内部