Hintergrund der Frage:
In Go gibt es oft Situationen, in denen die eingebauten Typen nicht ausreichen und ein eigener Datentyp mit Methoden definiert werden muss, um Logik zu kapseln und die Funktionalität zu erweitern. Dies wird durch die Erstellung von benutzerdefinierten Typen (type) und Methoden (func (r Receiver) MethodName()) erreicht.
Problematik:
Einsteiger-Entwickler verwechseln häufig, worin der Unterschied zwischen der Deklaration eines neuen Typs basierend auf einem vorhandenen besteht. Wie implementiert man Methoden richtig? Wie wird das Kopieren, die Übertragung durch Wert/Zeiger gelöst? Sie machen Fehler in Bezug auf Sichtbarkeit, den Typ des Receivers und die Arbeit mit eingebetteten Structs.
Lösung:
Zur Definition eines eigenen Typs wird das Schlüsselwort type verwendet. Methoden werden durch den Receiver (Empfänger) implementiert – das ist wichtig für die Arbeit mit Schnittstellen.
Beispielcode:
type MyInt int func (m MyInt) Double() int { return int(m) * 2 } // Für Strukturen: type User struct { Name string Age int } func (u *User) Birthday() { u.Age++ } var u = User{"Alice", 30} u.Birthday() // Age = 31
Wichtige Merkmale:
Erben benutzerdefinierte Typen die Methoden des Basistyps?
Nein. Wenn type MyInt int definiert wird, hat MyInt keine Methoden von int. Der Aufruf von String() oder anderen Methoden des Basistyps funktioniert nicht.
Kann man Methoden für einen Typalias definieren?
Für Aliase (type MyType = ExistingType) können keine Methoden hinzugefügt werden. Methoden werden nur für neue Typen (type MyType ExistingType) definiert, nicht für Pseudonyme.
Welchen Receiver sollte man verwenden: Zeiger oder Wert?
Wenn die Methode das Objekt ändern soll, ist es besser, einen Zeiger zu verwenden. Der Value Receiver kopiert die Struktur, was zu unerwartetem Verhalten führen kann, wenn die Struktur z.B. Slice- oder Kartenfelder enthält.
Beispielcode:
type Counter struct { value int } func (c *Counter) Inc() { c.value++ } func main() { c := Counter{} c.Inc() // nur mit Zeiger wird der Wert geändert }
Ein Programmierer hat type MySlice []int erstellt und erwartet, dass die Methoden []int, z.B. append, wie Methoden auf dem Typ MySlice funktionieren. Am Ende stellte sich heraus, dass es keine Methoden gibt und man MySlice nicht direkt als []int verwenden kann.
Vorteile:
Nachteile:
Es wurde type Counter int mit der Methode Inc definiert, was es ermöglichte, ihn an mehreren Stellen im Programm mit gemeinsamer Logik ohne wiederholten Code zu verwenden.
Vorteile:
Nachteile: