Go 为什么我会得到一个“;无法分配";将结构的值设置为映射中的值时出错?

Go 为什么我会得到一个“;无法分配";将结构的值设置为映射中的值时出错?,go,Go,新的开始。遇到此错误,但未能找到原因或理由: 如果我创建一个结构,我显然可以分配和重新分配值,没有问题: type Person struct { name string age int } func main() { x := Person{"Andy Capp", 98} x.age = 99 fmt.Printf("age: %d\n", x.age) } 但如果结构是映射中的一个值: type Person struct { name string

新的开始。遇到此错误,但未能找到原因或理由:

如果我创建一个结构,我显然可以分配和重新分配值,没有问题:

type Person struct {
 name string
 age int
}

func main() {
  x := Person{"Andy Capp", 98}
  x.age = 99
  fmt.Printf("age: %d\n", x.age)
}
但如果结构是映射中的一个值:

type Person struct {
     name string
     age int
 }

type People map[string]Person

func main() {
  p := make(People)
  p["HM"] = Person{"Hank McNamara", 39}
  p["HM"].age = p["HM"].age + 1
  fmt.Printf("age: %d\n", p["HM"].age)
}
我得到
无法分配给p[“HM”]。年龄
。就这样,没有其他信息

我找到了解决这个问题的方法-在Person上创建一个
incrementAge
func,可以调用它并将结果分配给map键,例如
p[“HM”]=p[“HM”].incrementAge()

但是,我的问题是,这个“无法分配”错误的原因是什么,为什么不允许我直接分配结构值?

p[“HM”]
不是一个常规值:,然后它们的值在内存中移动,旧的位置变得过时。若映射中的值被视为常规可寻址值,那个么
map
实现的内部将被暴露

因此,相反,
p[“HM”]
在规范中是一个稍微不同的东西,称为“映射”;如果在规范中搜索短语“index expression”,您将看到可以对它们执行某些操作,例如读取它们、分配它们,以及在递增/递减表达式中使用它们(对于数字类型)。但你不可能什么都做。他们本可以选择实施更多的特殊情况,但我猜他们不只是为了保持简单

您的方法在这里似乎很好--您将其更改为常规赋值,这是一种特别允许的操作。另一种方法(可能适用于您希望避免复制的较大结构?)是,您可以通过以下方式修改基础对象:

package main

import "fmt"

type Person struct {
    name string
    age  int
}

type People map[string]*Person

func main() {
    p := make(People)
    p["HM"] = &Person{"Hank McNamara", 39}
    p["HM"].age += 1
    fmt.Printf("age: %d\n", p["HM"].age)
}

作业的左侧必须为“可寻址”

每个左手边操作数必须是可寻址的,一个MAP索引表达式,或者(for for =赋值)空白标识符。 及

操作数必须是可寻址的,即变量、指针间接寻址或切片索引操作;或可寻址结构操作数的字段选择器;或可寻址数组的数组索引操作

正如@twoo的评论,
p[“HM”]
是不可寻址的。
但是,规范中没有这样的定义来说明什么是“可寻址结构操作数”。我认为他们应该为它添加一些描述。

p[“HM”]
不是一个非常常规的指针值,因为映射中的值在内存中移动,当映射增长时,旧的位置变得无效。因此,您不能对它执行常规指针可以执行的所有操作。除了您的解决方案(将其更改为赋值,这是允许的操作之一,在这里似乎很好),另一种方法(可能适用于大型对象?)是将贴图值设置为常规的旧指针,您可以通过以下方式修改基础对象:使用
p[“HM”]如果你搜索“索引表达式”,你可以读取值,分配一个新的整数值,删除,递增/递减数值。啊,这很有意义-我曾经尝试过做一个指针
*Person
,但我想我忘了创建带有
&
的引用-仍然习惯了这一点。谢谢,让它成为一个答案,我接受…^^^^^这一点(和其他答案)是通过一个简单而明显的
[go]地图无法分配的
搜索找到的。你是对的,我做了搜索,但不是正确的搜索。我感到惭愧:(但我认为还有一点是,“不能分配”错误意味着“分配的左侧不是一个可寻址的值”(imo将是一个更好、更可搜索的消息)建议使用指针映射,例如
map[string]* MyStults/CODE为我解决了类似的问题。那么为什么STL C++中的无序映射可以支持面向相同的重新分配问题的寻址?@ HuntTeTead只是不同的哈希映射设计。我不是STL专家,但可以是,例如,大小调整的基础数组只存储指针到值。(或更大的部件——钥匙/钱包对、水桶等)所以,增长数组意味着围绕指针而不是值来拖动。这有点像在GHASHMAP中存储指针到值,但是隐式地进行。其他C++的HASH图,像在主数组中存储值,当它长大时使迭代器无效。@ HuntTyTead可能更喜欢Go/StudioHasyMMAP方法来避免HA。如果您不关心项的移动,则可以在读取项时跟随指针(可能等待缓存未命中)。如果您需要不移动值,则可能更喜欢无序映射方法。请注意,Go的方法是项移动,但不能创建悬空指针(因为语言禁止获取项的地址)不是C++中的选项(在这里你可以选择大多数的地址)。所以设计者可能认为稳定的条目地址会使无序的地图更容易安全地使用。@ TooToWo.2.3KS。当我们引用地图时,返回的值被返回“值返回”,这是GLang-map设计与STL相比的关键差异。