为什么我得到一个“不能分配”的错误时,设置值的结构作为一个值在地图?

新手上路。遇到了这个错误,却没有找到原因或理由:

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

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)
}

我得到 cannot assign to p["HM"].age。就是这样,没有其他信息。 http://play.golang.org/p/VRlSItd4eP

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

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

81579 次浏览

p["HM"]不是一个常规的 可寻址的值: 散列映射可以在运行时增长,然后它们的值在内存中移动,旧的位置变得过时。如果映射中的值被视为常规可寻址值,那么 map实现的那些内部结构就会暴露出来。

So, instead, p["HM"] is a slightly different thing called a "map 索引表达式" in the spec; if you search the spec for the phrase "index expression" you'll see you can do certain things with them, like read them, assign to them, and use them in increment/decrement expressions (for numeric types). But you can't do everything. They could have chosen to implement more special cases than they did, but I'm guessing they didn't just to keep things simple.

Your approach seems good here--you change it to a regular assignment, one of the specifically-allowed operations. Another approach (maybe good for larger structs you want to avoid copying around?) is to 使映射值成为一个普通的旧指针 that you can modify the underlying object through:

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)
}

赋值的左边必须是“可寻址的”。

Https://golang.org/ref/spec#assignments

Each left-hand side operand must be addressable, a map index expression, or (for = assignments only) the blank identifier.

https://golang.org/ref/spec#Address_operators

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

作为@twotwotwo 的评论,p["HM"]是不可寻址的。 but, there is no such definition show what is "addressable struct operand" in the spec. I think they should add some description for it.