Подтвердить что ты не робот

Почему я получаю ошибку "не могу назначить" при установке значения для структуры как значения на карте?

Новое, чтобы идти. Обнаружена эта ошибка и не повезло найти причину или обоснование для нее:

Если я создам структуру, я могу, очевидно, назначить и повторно назначить значения без проблем:

type Person struct {
 name string
 age int
}

func main() {
  x := Person{"Andy Capp", 98}
  x.age = 99
  fmt.Printf("age: %d\n", x.age)
}

но если struct является одним значением на карте:

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

Я нашел способ обойти это: создание функции incrementAge fun на Person, которая может быть вызвана, и результат, назначенный ключу карты, например p["HM"] = p["HM"].incrementAge().

Но, на мой вопрос, в чем причина этой ошибки "не могу назначить", и почему я не должен позволять напрямую присваивать значение struct?

4b9b3361

Ответ 1

p["HM"] не является обычным адресуемым значением: hashmaps может расти во время выполнения, а затем их значения перемещаются в памяти, а старые местоположения устаревают. Если значения в картах считались регулярными адресными значениями, эти внутренние функции реализации map были бы открыты.

Итак, p["HM"] - это немного другая вещь, называемая "map индексное выражение "в спецификации; если вы будете искать спецификацию для фразы "выражение индекса", вы увидите, что вы можете делать с ними определенные вещи, например, читать их, назначать им и использовать их в выражениях increment/decment (для числовых типов). Но вы не можете все. Они могли бы выбрать более сложные случаи, чем они, но я предполагаю, что они не просто упростили ситуацию.

Ваш подход кажется хорошим здесь - вы меняете его на обычное задание - одну из специально разрешенных операций. Другой подход (возможно, подходит для больших структур, которые вы хотите избежать копирования?) Заключается в сделать значение карты обычным старым указателем, в котором вы можете изменить базовый объект через:

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

Ответ 2

левая часть задания должна быть "адресной".

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

Каждый операнд левой стороны должен быть адресуемым, выражением индекса карты или (только для = присваивания) пустым идентификатором.

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

Операнд должен быть адресуемым, то есть либо переменной, либо указателем, либо индексированием фрагмента; или селектор поля адресного структурного операнда; или операцию индексирования массива адресного массива.

как @twotwotwo comment, p["HM"] не адресуется. но, нет такого определения, покажите, что такое "адресуемый операнд структуры" в sepc. Я думаю, что они должны добавить описание для этого.