Jest dla mnie bardzo niejasne, w którym przypadku chciałbym użyć odbiornika wartości zamiast zawsze używać odbiornika wskaźnika.
Podsumowując z dokumentów:
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
Plik docs mówi także „Dla typów, takich jak podstawowe typy, plasterki i małych strukturach, odbiornik wartość jest bardzo tanie, więc chyba semantyka metody wymaga wskaźnik, odbiornik wartość jest efektywny i przejrzysty”.
Po pierwsze , mówi, że jest „bardzo tani”, ale pytanie brzmi raczej, czy jest tańszy niż odbiornik wskaźnika. Więc zrobiłem mały test porównawczy (kod w istocie) który pokazał mi, że odbiornik wskaźnika jest szybszy nawet dla struktury, która ma tylko jedno pole tekstowe. Oto wyniki:
// Struct one empty string property
BenchmarkChangePointerReceiver 2000000000 0.36 ns/op
BenchmarkChangeItValueReceiver 500000000 3.62 ns/op
// Struct one zero int property
BenchmarkChangePointerReceiver 2000000000 0.36 ns/op
BenchmarkChangeItValueReceiver 2000000000 0.36 ns/op
(Edycja: należy pamiętać, że drugi punkt stał się nieważny w nowszych wersjach go, patrz komentarze) .
Drugi punkt mówi, że jest „wydajny i przejrzysty”, co jest bardziej kwestią gustu, prawda? Osobiście wolę spójność, używając wszędzie w ten sam sposób. W jakim sensie efektywność? pod względem wydajności wydaje się, że wskaźniki są prawie zawsze bardziej wydajne. Kilka testów z jedną właściwością int wykazało minimalną przewagę odbiornika wartości (zakres 0,01-0,1 ns / op)
Czy ktoś może mi powiedzieć o przypadku, w którym odbiornik wartości ma wyraźnie większy sens niż odbiornik wskaźnika? A może robię coś źle w teście porównawczym, czy przeoczyłem inne czynniki?
Odpowiedzi:
Zwróć uwagę, że FAQ wspomina o spójności
Jak wspomniano w tym wątku :
Teraz:
Komentarz Code Review może pomóc:
Pogrubiona część znajduje się na przykład w
net/http/server.go#Write()
:źródło
The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers
Właściwie to nieprawda. Zarówno metody odbiornika wartości, jak i metody odbiornika wskaźnika mogą być wywoływane na wskaźniku o poprawnym typie lub wskaźniku niebędącym wskaźnikiem. Niezależnie od tego, na jakiej metodzie jest wywoływana, w treści metody identyfikator odbiorcy odnosi się do wartości by-copy, gdy używany jest odbiornik wartości, oraz wskaźnika, gdy używany jest odbiornik wskaźnika: Zobacz play.golang.org/p / 3WHGaAbURMInt(5).increment_by_one_ptr()
. Podobnie cecha definiująca metodęincrement_by_one_ptr
nie będzie zadowalająca z wartością typuInt
.Aby dodać do @VonC świetną, pouczającą odpowiedź.
Dziwię się, że nikt tak naprawdę nie wspomniał o kosztach utrzymania, gdy projekt się rozrasta, starzy deweloperzy odchodzą i przychodzi nowy. Go z pewnością jest młodym językiem.
Ogólnie rzecz biorąc, staram się unikać wskazówek, kiedy mogę, ale mają one swoje miejsce i piękno.
Używam wskaźników, gdy:
Na przykład:
Powody, dla których unikam wskazówek:
Moja praktyczna zasada: napisz jak najwięcej hermetyzowanych metod, takich jak:
AKTUALIZACJA:
To pytanie zainspirowało mnie do dokładniejszego zbadania tematu i napisania na ten temat wpisu na blogu https://medium.com/gophersland/gopher-vs-object-oriented-golang-4fa62b88c701
źródło