2013-08-06 9 views
5

Powiedzmy mam proste struct A o właściwości String B:Mapa elemencie vs tablicy kodowanym w Go

type A struct { 
    B string 
} 

Poniższy kod przy użyciu tablicy A typy:

testArray := []A{A{}} 
testArray[0].B = "test1" 
fmt.Println(testArray[0].B) 

Wydruk "test1" zgodnie z oczekiwaniami.

Ale ten kod, który wydaje się równie prosta:

testMap := make(map[string]A) 
testMap["key"] = A{} 
testMap["key"].B = "test2" 
fmt.Println(testMap["key"].B) 

Will nie wydrukować "test2", ale zamiast spowoduje następujący błąd:

cannot assign to testMap["key"].B

Więc dlaczego przypisanie do podwłasność w mapie powoduje błąd podczas przypisywania do podwłasności w pracy tablicowej zgodnie z oczekiwaniami? Chcę wiedzieć zarówno, dlaczego to nie działa dla map i dlaczego działa dla tablic. Chciałbym także pokusić się o spekulacje, dlaczego zaprojektowali język z tą różnicą między dwiema strukturami danych.

+0

'testArray' nie jest" tablicą ". To jest "kawałek". "Array" to coś innego. – newacct

Odpowiedz

10

Odpowiedziałem trochę na liście mailingowej, ale krótkie wyjaśnienie jest takie, że to nie działa, ponieważ wpisy map nie są adresowalne. Oznacza to, że nie można wziąć adresu wpisu na mapie. A to dlatego, że dodanie nowej wartości do mapy może spowodować przesunięcie wpisów mapy, tak aby adresy zmieniały się. Ponieważ nie można wpisać adresu pozycji na mapie, wszystkie operacje na mapie używają całych wartości: kopiowanie całej wartości z mapy, dodawanie całości do mapy. Przypisanie do jednego pola struktury na mapie wymagałoby operacji odczytu-modyfikacji-zapisu, mapy te nie obsługują (mogą, ale nie mają, a ich utrzymanie jest kosztowne).

Elementy w tablicach i plasterkach są adresowalne, ponieważ nie poruszają się po utworzeniu.

+1

To odpowiedziało na moje pytanie. To nie "tylko dlatego, że tak zostało zaprojektowane" lub "magia" czy coś takiego, powód dlaczego tablice na to pozwalają, a mapy nie mają sensu. Dziękuję Ci! – GreenMachine

+0

Również dogłębna odpowiedź jest jeszcze bardziej pomocna. Może warto opublikować to wszystko tutaj, ale na razie tutaj jest link do niego: https://groups.google.com/d/msg/golang-nuts/FCcLsuWsF_U/qk6SLNcHvJIJ – GreenMachine

2

Elementem tablicy jest lvalue. W przypadku map jest nieco bardziej złożony. W:

m := map[T]U{} 
m[T(expr)] = U(expr) 

LHS m[T(expr)]jest lwartością. Jednak w:

type U struct{ 
     F V 
} 

m := map[T]U{} 
m[T(expr)].F = 34 

LHS m[T(expr)].F nie jest już lwartością. Pierwsza część, m[T(expr)], ocenia wystąpienie typu U. Ta instancja jest "pływająca", nie ma już domu. Przypisanie czegoś do jego pól jest z pewnością błędem, więc kompilator krzyczy.

To mniej więcej taka sama, jak różnica między:

var v U 
v.F = 42 // ok 
U{}.F = 42 // not ok 

Góra rozwiązać ten problem, można użyć wskaźnika do struktury:

m := map[T]*U{} 
m[T(expr)].F = 42 

Mapa pierwszy daje wskaźnik do U który jest następnie używany do ustawiania pola.

1

Technicznie, zgodnie z językiem odniesienia, wyrażenie testmap["key"].B nie jest addressable, więc nie może być używane jako lewa strona assignment.

Tak więc pytanie może wymagać przeniesienia do: dlaczego to wyrażenie nie jest adresowalne? Nie jestem do końca tego pewien ...

... ah. To dlatego, że testmap["key"] daje nam kopię struktury. Mutowanie tej kopii prawdopodobnie nie jest tym, co chcemy zrobić, ponieważ nie wpłynie to na oryginalną strukturę mapy.

4

Problem polega na tym, że w przykładzie mapy testMap["key"] zwraca literał, a nie wskaźnik. Oznacza to, że modyfikowanie go jest bez znaczenia, więc kompilator go ignoruje.Jest to w zasadzie równoważne:

v := testMap["key"] 
v.B = "test2" 

... a potem nigdy nie używając v ponownie. Nie ma żadnego efektu. Jest to równoznaczne z nieosiągnięciem tych dwóch linii w pierwszej kolejności. Dlatego kompilator nie pozwoli ci tego zrobić. Z drugiej strony, gdybyś zrobił to jako mapa z wskazówkami na A, byłbyś w biznesie. Ten byłoby kompilacji:

testMap := make(map[string]*A) 
testMap["key"] = &A{} 
testMap["key"].B = "test2" 

Dlatego, że to działa to, że dereferencing i przypisanie wartości wskaźnika robi mieć wpływ.

+0

Podoba mi się to wytłumaczenie dla map, ale co różni się tablicami? Tablice również nie zwracają wskaźników, więc dlaczego to działa w przykładzie tablicy? – GreenMachine

+0

... magia, myślę. – joshlf

+0

Myślę, że to po prostu sposób, w jaki język jest zaprojektowany. Tablice są magiczne. Teoretycznie mogliby to zrobić również za pomocą map, ale z jakiegoś powodu tak się nie stało. – joshlf