Es ist für mich sehr unklar, in welchem Fall ich einen Wertempfänger verwenden möchte, anstatt immer einen Zeigerempfänger zu verwenden.
So rekapitulieren Sie aus den Dokumenten:
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
In den Dokumenten heißt es auch: "Für Typen wie Basistypen, Slices und kleine Strukturen ist ein Wertempfänger sehr billig. Wenn die Semantik der Methode keinen Zeiger erfordert, ist ein Wertempfänger effizient und klar."
Der erste Punkt besagt, dass es "sehr billig" ist, aber die Frage ist mehr, ob es billiger ist als der Zeigerempfänger. Also habe ich einen kleinen Benchmark (Code on Gist) erstellt, der mir zeigte, dass der Zeigerempfänger selbst für eine Struktur mit nur einem Zeichenfolgenfeld schneller ist. Dies sind die Ergebnisse:
// 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
(Bearbeiten: Bitte beachten Sie, dass der zweite Punkt in neueren Go-Versionen ungültig wurde, siehe Kommentare) .
Der zweite Punkt besagt, dass es "effizient und klar" ist, was eher Geschmackssache ist, nicht wahr? Persönlich bevorzuge ich Konsistenz, indem ich sie überall gleich verwende. Effizienz in welchem Sinne? In Bezug auf die Leistung scheint es, dass Zeiger fast immer effizienter sind. Nur wenige Testläufe mit einer int-Eigenschaft zeigten einen minimalen Vorteil des Value-Empfängers (Bereich von 0,01 bis 0,1 ns / op).
Kann mir jemand einen Fall sagen, in dem ein Wertempfänger eindeutig sinnvoller ist als ein Zeigerempfänger? Oder mache ich im Benchmark etwas falsch, habe ich andere Faktoren übersehen?