Lektionen des Moduls (2/5)
Methoden: Wert- vs. Zeiger-Receiver
Eine Methode in Go ist eine Funktion mit einem Empfänger: einem Special
zwischen func und dem Methodennamen deklarierter Parameter, der die bindet
Methode zu einem Typ. Es gibt keine Klassen: Methoden können definiert werden
Jeder benannte Typ, der im aktuellen Paket deklariert ist.
Syntax
type Person struct {
Name string
}
func (p Person) Greet() string {
return "ciao " + p.Name
}
p := Person{Name: "Ada"}
fmt.Println(p.Greet()) // "ciao Ada"Der Empfänger p Person macht Greet zu einer Methode von Person. Im Inneren
Methode ist p eine Variable wie jede andere.
Wertempfänger vs. Zeigerempfänger
// VALUE receiver: operates on a COPY of the value
func (p Person) NameUpper() string {
return strings.ToUpper(p.Name)
}
// POINTER receiver: operates on the original value, can mutate it
func (p *Person) Rename(n string) {
p.Name = n
}Mit einem Zeigerempfänger können Sie den Empfänger modifizieren und die Änderungen vornehmen sind außerhalb der Methode sichtbar. Mit einem Wertempfänger können Sie das nicht – Sie würden es tun Ändern Sie nur die lokale Kopie.
p := Person{Name: "Ada"}
p.Rename("Grace")
fmt.Println(p.Name) // "Grace" — change is visibleWann sollte ein Zeigerempfänger verwendet werden?
Praktische Regeln, in der Reihenfolge ihrer Priorität:
- Sie müssen den Empfänger ändern → Zeigerempfänger. Obligatorisch.
- Die Struktur ist groß (Dutzende Felder, Arrays darin) → Zeiger Empfänger, um teure Kopien zu vermeiden.
- Konsistenz: Wenn MINDESTENS eine Methode für den Typ einen Zeigerempfänger hat, verwenden Sie ein Zeigerempfänger auch für die anderen. Eine sehr wichtige Tagung für Schnittstellen (Modul 6).
- Kleine, unveränderliche „Wert“-Typen (Zeit. Zeit, komplexe Zahlen, klein Strukturen) → Wertempfänger, besser lesbar.
Methoden für Nicht-Strukturtypen
Sie können Methoden für jeden in Ihrem Paket deklarierten NAMED-Typ definieren:
type Celsius float64
func (c Celsius) ToFahrenheit() float64 {
return float64(c)*9/5 + 32
}
t := Celsius(20)
fmt.Println(t.ToFahrenheit()) // 68Sie können sie nicht für Typen aus anderen Paketen (z. B. int, string) definieren: Sie müssen
Erstellen Sie zunächst einen lokalen benannten Typ.
Probieren Sie es aus
Fügen Sie eine Greet()-String-Methode (Wertempfänger) zu Person hinzu, die „ciao <Name>“ zurückgibt.
Hinweis anzeigen
Empfänger in Klammern VOR dem Methodennamen.
Lösung nach 3 Versuchen verfügbar
Fügen Sie eine Rename(n string)-Methode mit einem POINTER-Empfänger hinzu, der p.Name ändert.
Hinweis anzeigen
Zeigerempfänger: `(p *Person)`.
Lösung nach 3 Versuchen verfügbar
Wann sollten Sie einen Zeigerempfänger (p *T) verwenden?
func (t ?T) M() { ... }Zusammenfassung
- Methode = Funktion mit einem Empfänger:
func (r T) Name(...) ... { ... }. - Wertempfänger: bearbeitet eine Kopie; Zeigerempfänger: arbeitet auf dem Original.
- Go führt die
T↔*T-Konvertierung automatisch am Anrufort durch. - Zeigerempfänger, wenn: Mutation + große Struktur + Konsistenz mit anderen Methoden des Typs.
- Mischen Sie niemals Wert- und Zeigerempfänger desselben Typs. – Methoden gelten für NAMED-Typen im aktuellen Paket (einschließlich Nicht-Strukturen).