go

¿Por qué obtengo un error de "no se puede asignar" al establecer el valor de una estructura como un valor en un mapa?



(2)

Esta pregunta ya tiene una respuesta aquí:

Nuevo para ir. Encontré este error y no tuve suerte de encontrar la causa o la razón para ello:

Si creo una estructura, obviamente puedo asignar y reasignar los valores sin problema:

type Person struct { name string age int } func main() { x := Person{"Andy Capp", 98} x.age = 99 fmt.Printf("age: %d/n", x.age) }

pero si la estructura es un valor en un mapa:

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

No cannot assign to p["HM"].age . Eso es todo, no hay otra información. http://play.golang.org/p/VRlSItd4eP

Encontré una forma de evitar esto: crear una función incrementAge en Person, a la que se puede llamar y asignar el resultado a la tecla del mapa, p["HM"] = p["HM"].incrementAge() Ej. p["HM"] = p["HM"].incrementAge() .

Pero, mi pregunta es, ¿cuál es la razón de este error de "no se puede asignar" y por qué no se me debe permitir asignar el valor de estructura directamente?


el lado izquierdo de la tarea debe ser "direccionable".

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

Cada operando del lado izquierdo debe ser direccionable, una expresión de índice de mapa o (solo para asignaciones =) el identificador en blanco.

y addressable

El operando debe ser direccionable, es decir, una operación de indexación indirecta, de puntero o variable; o un selector de campo de un operando de estructura direccionable; o una operación de indexación de matriz de una matriz direccionable.

como comentario de @ twotwotwo, p["HM"] no es direccionable. pero, no existe tal definición que muestre qué es "operando de estructura direccionable" en el sepc. Creo que deberían agregar alguna descripción para ello.


p["HM"] no es un valor addressable : los hashmaps pueden crecer en tiempo de ejecución , y luego sus valores se mueven en la memoria y las ubicaciones antiguas quedan obsoletas. Si los valores en los mapas se trataran como valores direccionables regulares, los elementos internos de la implementación del map quedarían expuestos.

Entonces, en cambio, p["HM"] es una cosa ligeramente diferente llamada " expresión de índice de mapa" en la especificación; si busca la especificación para la frase "expresión de índice" verá que puede hacer ciertas cosas con ellos, como leerlos, asignarlos y usarlos en expresiones de incremento / decremento (para tipos numéricos). Pero no puedes hacer todo. Podrían haber optado por implementar más casos especiales que lo que hicieron, pero supongo que no lo hicieron solo para simplificar las cosas.

Su enfoque parece bueno aquí: lo cambia a una asignación regular, una de las operaciones específicamente permitidas. Otro enfoque (¿tal vez bueno para estructuras más grandes que desea evitar copiar?) Es hacer que el valor del mapa sea un puntero antiguo regular que pueda modificar el objeto subyacente a través de:

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