2015-09-24 13 views
25

New to Go. Napotkał ten błąd i nie miał szczęścia w znalezieniu przyczyny lub uzasadnienie dla niego:Dlaczego pojawia się błąd "nie można przypisać" podczas ustawiania wartości do struct jako wartość na mapie?

Jeśli utworzyć struct, mogę oczywiście przypisać i ponowne przypisanie wartości nie ma problemu:

type Person struct { 
name string 
age int 
} 

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

ale jeśli struct to jedna wartość na mapie:

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

Dostaję cannot assign to p["HM"].age. To wszystko, żadnych innych informacji. http://play.golang.org/p/VRlSItd4eP

Znalazłem sposób obejścia tego - utworzenie funkcji incrementAge na osobie, która może zostać wywołana, a wynik przypisany do klawisza mapy, np. p["HM"] = p["HM"].incrementAge().

Ale moje pytanie brzmi, jaki jest powód tego błędu "nie można przypisać" i dlaczego nie powinienem mieć możliwości bezpośredniego przypisania wartości struct?

+1

'p [" HM "]' nie jest dość regularną wartością wskaźnika, ponieważ wartości na mapie są przenoszone w pamięci, a stare lokalizacje tracą ważność, gdy mapa rośnie. Więc nie możesz wykonywać wszystkich operacji na tym, co możesz zrobić na zwykłym wskaźniku. Poza twoim rozwiązaniem (zmień to na przypisanie, jedną z dozwolonych operacji, która wydaje się tutaj dobra), innym podejściem (może dobrze dla dużych obiektów?) Jest sprawienie, by wartość mapy była zwykłym starym wskaźnikiem, który * możesz * modyfikować obiekt przez: http://play.golang.org/p/n5C4CsKOAV – twotwotwo

+0

Konkretne rzeczy, które możesz zrobić z 'p [" HM "]' są rozrzucone wokół [the spec] (https://golang.org/ref/ spec), jeśli wyszukujesz "wyrażenie indeksu": możesz odczytać wartość, przypisać nową całą wartość, usunąć, zwiększyć/zmniejszyć wartości liczbowe. – twotwotwo

+0

ah to ma sens - próbowałem zrobić wskaźnik "* Person" w jednym punkcie, ale myślę, że zapomniałem utworzyć odniesienie z '&' - wciąż się do tego przyzwyczajam. dziękuję, zrób odpowiedź, a ja bym zaakceptował ... – sbeam

Odpowiedz

35

p["HM"] nie jest dość regularną wartością addressable: hashmaps can grow at runtime, a ich wartości zostają przeniesione do pamięci, a stare lokalizacje stają się nieaktualne. Jeśli wartości na mapach były traktowane jako regularne wartości adresowalne, te elementy wewnętrzne implementacji map zostałyby ujawnione.

Tak więc zamiast tego p["HM"] to nieco inna rzecz zwana "mapą index expression" w specyfikacji; jeśli przeszukasz specyfikację dla wyrażenia "wyrażenie indeksu" zobaczysz, że możesz zrobić z nimi pewne rzeczy, na przykład je przeczytać, przypisać do nich i użyć ich w wyrażeniach przyrostu/dekrementacji (dla typów liczbowych). Ale nie możesz zrobić wszystkiego. Mogli wybrać specjalne przypadki niż te, ale domyślam się, że nie tylko po to, aby wszystko było proste.

Twoje podejście wydaje się tutaj dobre - zmieniasz je na zwykłe zadanie, jedną z wyraźnie dozwolonych operacji. Innym podejściem (? Może dobre dla większych strukturach chcesz uniknąć kopiowanie wokół) jest make the map value a regular old pointer które można modyfikować podstawowych przedmiotów przez:

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

lewej stronie przypisania musi B „adresowalny”.

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

Każdy bok lewy operand musi być adresowalne, wyrażenie indeksu map lub (tylko dla zadań) = pustym identyfikatorem.

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

Argument musi być adresowalne, czyli albo zmienna, wskaźnik pośredniość lub plaster działanie indeksowanie; lub selektor pól adresowalnego operandu strukturalnego; lub operacja indeksowania tablic adresowalnej tablicy.

jako komentarz @ twotwotwo, p["HM"] nie można adresować. , ale nie ma takiej definicji pokazują, co jest "adresowalnym operandem strukturalnym" w sepc. Myślę, że powinni dodać jakiś opis.

Powiązane problemy