Map Go中结构与结构数组的映射

Map Go中结构与结构数组的映射,map,struct,go,slice,Map,Struct,Go,Slice,假设我有一个简单的结构a和一个字符串属性b: type A struct { B string } 以下代码使用类型的数组: testArray := []A{A{}} testArray[0].B = "test1" fmt.Println(testArray[0].B) 将按预期打印“test1” 但这段代码似乎同样简单: testMap := make(map[string]A) testMap["key"] = A{} testMap["key"].B = "test2" f

假设我有一个简单的结构a和一个字符串属性b:

type A struct {
    B string
}
以下代码使用类型的数组:

testArray := []A{A{}}
testArray[0].B = "test1"
fmt.Println(testArray[0].B)
将按预期打印“test1”

但这段代码似乎同样简单:

testMap := make(map[string]A)
testMap["key"] = A{}
testMap["key"].B = "test2"
fmt.Println(testMap["key"].B)
不会打印“test2”,但会导致以下错误:

无法分配给testMap[“键”]。B

因此,为什么分配给映射中的子属性会导致错误,而分配给数组中的子属性会按预期工作?我想知道为什么这不适用于映射,为什么它适用于数组。我还想知道为什么他们设计语言时会考虑这两种数据结构之间的差异。

数组元素是一种特殊的元素。有了地图,情况就复杂了一点。在:

m := map[T]U{}
m[T(expr)] = U(expr)
LHS
m[T(expr)]
是一个左值。然而,在:

type U struct{
        F V
}

m := map[T]U{}
m[T(expr)].F = 34
LHS
m[T(expr)].F
不再是左值。第一部分,
m[T(expr)]
计算为
U
类型的实例。那个实例是“浮动的”,它不再有家了。将某些内容分配给它的字段肯定是一个错误,因此编译器会大喊大叫

这与以下两者的区别大致相同:

var v U
v.F = 42 // ok
U{}.F = 42 // not ok
要解决此问题,可以使用指向结构的指针:

m := map[T]*U{}
m[T(expr)].F = 42

映射首先产生一个指向
U
的指针,然后用于设置字段。

从技术上讲,根据语言参考,表达式
testmap[“key”].B
不是,因此它不能用作字段的左侧

因此,问题可能需要转移到:为什么这个表达不可寻址?我还不太确定


。。。啊。这是因为
testmap[“key”]
正在返回结构的副本。变异该副本可能不是我们想要做的,因为它不会影响映射中的原始结构。

问题是在映射示例中,
testMap[“key”]
返回一个文本,而不是指针。这意味着修改它是没有意义的,因此编译器不允许它。这基本上相当于:

v := testMap["key"]
v.B = "test2"
。。。然后再也不要使用
v
。它没有效果。这相当于从一开始就不执行这两行。这就是为什么编译器不让你这么做。另一方面,如果你把它做成一张指向a的地图,你就可以做生意了。这将汇编:


这样做之所以有效,是因为取消引用和指定指针值确实会产生影响。

我在邮件列表中给出了详细的回答,但简短的解释是,这不起作用,因为地图条目不可寻址。这意味着你不能在地图中获取条目的地址。这是因为向映射添加新值可能会导致映射条目四处移动,从而导致地址发生变化。因为不能获取映射中某个条目的地址,所以所有映射操作都使用整数值:从映射中复制整数值,将整数值添加到映射中。分配给映射中结构的一个字段将需要一个读-修改-写操作,而映射不支持该操作(它们可以,但不支持,而且支持它们会有成本)


数组和切片中的元素是可寻址的,因为它们在创建后不会四处移动。

我喜欢对映射的这种解释,但数组有什么不同?数组也不返回指针,那么为什么在数组示例中这样做呢?我认为这就是语言的设计方式。阵列很神奇。理论上,他们也可以用地图来做,但我想,出于某种原因,他们没有这样做。这是暂时的,不是文字。数组并不神奇。数组或切片的索引是相对于其起点的偏移量。映射的索引返回存储桶中某个项目的地址,该地址可能会随着添加更多项目而变得无效。因此,您是说
m[k]=v
不是一个原子操作(一旦查找了值)?这回答了我的问题。这并不是“仅仅因为它是这样设计的”或“神奇”之类的,为什么阵列允许这样做,而地图没有意义。非常感谢。而且,你深入的回答更有帮助。这可能值得在这里发布,但现在,这里有一个链接:
testArray
不是一个“数组”。这是一个“切片”。“数组”是不一样的。
testMap := make(map[string]*A)
testMap["key"] = &A{}
testMap["key"].B = "test2"