Value vs Pointer Receiver in Go: Was wählen?

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Value Receiver vs. Pointer Receiver: Ein unendlicher Duell

\n\n

Wenn Sie auch nur einmal in Go geschrieben haben, sind Sie sicherlich auf diese Frage gestoßen. Sie öffnen Stack Overflow – und dort tausende Aufrufe, hunderte Kommentare, und jeder zweite Anfänger (und nicht nur der) zerbricht sich den Kopf: "Was soll ich nun wählen? Value Receiver oder Pointer Receiver?"

\n\n

Spoiler: Es gibt keine richtige Antwort für alle Fälle. Aber es gibt klare Regeln, die Ihnen in 95% der Fälle helfen, keinen Fehler zu machen. Und heute werden wir sie ein für alle Mal durchgehen.

\n\n

In diesem Artikel werde ich nicht einfach die trockene Dokumentation übersetzen. Wir gehen durch reale Anwendungsfälle, betrachten Performance, Mutabilität, Interfaces und sogar, wie die Go-Community zu den verschiedenen Ansätzen steht. Los geht's!

\n\n

Was ist ein Receiver in Go?

\n\n

Für diejenigen, die die Sprache gerade erst kennenlernen: Ein Receiver ist ein Parameter, der eine Funktion mit einem Typ verbindet. So werden in Go Methoden implementiert.

\n\n
type User struct {\n    Name string\n    Age  int\n}\n\n// Value receiver\nfunc (u User) Greet() string {\n    return "Hallo, ich bin " + u.Name\n}\n\n// Pointer receiver\nfunc (u *User) Birthday() {\n    u.Age++\n}\n
\n\n

Im ersten Fall arbeiten wir mit einer Kopie der Struktur. Im zweiten Fall mit einem Zeiger auf das Original. Es scheint eine Kleinigkeit zu sein. Aber aus dieser Kleinigkeit erwachsen ganze architektonische Entscheidungen.

\n\n

Wann man den Value Receiver verwendet

\n\n

Beginnen wir mit der einfachsten und sichersten Variante.

\n\n

1. Die Methode verändert den Empfänger nicht

\n\n

Dies ist die goldene Regel. Wenn die Methode nur Daten liest und nichts ändert – verwenden Sie den Value Receiver. Das ist sicher, vorhersagbar und verständlich.

\n\n
type Rectangle struct {\n    Width, Height float64\n}\n\nfunc (r Rectangle) Area() float64 {\n    return r.Width * r.Height\n}\n
\n\n

Niemand erwartet, dass die Berechnung der Fläche das Rechteck selbst verändert. Der Value Receiver ist hier die ideale Wahl.

\n\n

2. Kleine Strukturen

\n\n

Wenn Ihre Struktur aus ein paar Feldern besteht (wie Rectangle oben), kostet das Kopieren praktisch nichts. Mehr noch, es kann schneller sein als die Arbeit mit einem Zeiger, weil die Daten auf dem Stack liegen, nicht auf dem Heap.

\n\n

3. Sicherheit und Unveränderlichkeit

\n\n

Manchmal möchten Sie bewusst garantieren, dass die Methode die ursprünglichen Daten nicht ändert. Der Value Receiver gibt Ihnen diese Garantie auf Compiler-Ebene.

\n\n
type Config struct {\n    Timeout int\n}\n\nfunc (c Config) WithTimeout(t int) Config {\n    c.Timeout = t\n    return c\n}\n
\n\n

Dies ist ein Muster der funktionalen Programmierung: Die Methode gibt eine neue Kopie zurück, ohne das Original zu berühren. Ideal für unveränderliche Konfigurationen.

\n\n

Wann man den Pointer Receiver wählt

\n\n

Und hier wird es richtig interessant. Der Pointer Receiver ist ein mächtiges Werkzeug, aber man muss vorsichtig damit umgehen.

\n\n

1. Die Methode verändert den Empfänger

\n\n

Dies ist der offensichtlichste Fall. Wenn Sie SetName, UpdateStatus oder Increment schreiben – brauchen Sie einen Zeiger.

\n\n
type Counter struct {\n    Value int\n}\n\nfunc (c *Counter) Increment() {\n    c.Value++\n}\n
\n\n

Ohne Zeiger würden Sie eine Kopie inkrementieren, und das Original bliebe unverändert. Ein klassischer Anfängerfehler.

\n\n

2. Große Strukturen

\n\n

Wenn Ihre Struktur hundert Bytes oder mehr wiegt, ist das Kopieren bei jedem Methodenaufruf teuer. Besonders, wenn die Methode in einer Schleife aufgerufen wird.

\n\n
type LargeData struct {\n    Buffer [1024]byte\n    Meta   map[string]interface{}\n}\n\n// Das bei jedem Aufruf zu kopieren ist schmerzhaft\nfunc (l *LargeData) Process() {\n    // Arbeiten mit dem Original\n}\n
\n\n

Hier ist der Pointer Receiver nicht nur eine Bequemlichkeit, sondern eine Performance-Optimierung.

\n\n

3. Wenn die Struktur einen Mutex enthält oder

Blogs

Buchempfehlungen