Geschichte der Frage:
Go hat ein einfaches, aber leistungsstarkes Konzept für Methoden und Schnittstellen implementiert, das auf Duck Typing basiert. Methoden können nur für benannte Typen (Struct oder Alias) definiert werden, während Schnittstellen eine Menge von Methoden darstellen. Dies ist der Schlüssel zu Polymorphismus und Abstraktionen, ohne dass eine explizite Angabe von implements erforderlich ist.
Problem:
Programmierer, die aus Java oder C# kommen, erwarten oft explizite Schlüsselwörter wie implements oder extends und sind verwirrt über die Unterschiede zwischen Methoden mit einem Receiver per Wert und per Zeiger, was zu unvorhersehbarem Verhalten und Fehlern bei der Implementierung von Schnittstellen führt.
Lösung:
Definition von Methode und Schnittstelle:
type User struct { Name string } func (u User) Greet() string { return "Hallo, " + u.Name } func (u *User) SetName(name string) { u.Name = name } type Greeter interface { Greet() string }
Schlüsselfeatures:
Kann man Methoden für einen Typ-Alias mit dem Basistyp int oder string deklarieren?
Ja, wenn es sich um einen benannten Typ handelt, z.B.:
type MyInt int func (m MyInt) Double() int { return int(m) * 2 }
Was ist der Unterschied zwischen der Implementierung einer Schnittstelle über Methoden mit Zeiger und Wert?
Wenn die Methode der Schnittstelle als (T) deklariert ist, dann implementieren sowohl T als auch *T die Schnittstelle. Wenn (*T), nur *T erfüllt die Schnittstelle. Dies ist entscheidend für die Übergabe der Struktur an Funktionen, die Schnittstellen akzeptieren.
Wie funktioniert der "zero value" für Schnittstellen und was passiert, wenn man eine Methode auf einem nil-Wert aufruft?
Eine nicht initialisierte Schnittstellenvariable ist nil, ein Versuch, eine Methode auf einem nil-Feld aufzurufen, wird paniken, wenn keine explizite nil-Zeigerbehandlung implementiert ist.
Der Typ ist mit Methoden per Zeiger (*T) deklariert, die Schnittstelle erwartet Methoden per Wert (T), und die Struktur kompiliert nicht, wenn sie in Schnittstellen verwendet wird. Versuch, eine Methode für eine Variable des Typs []User zu deklarieren, und nicht für den Typ User.
Vorteile:
Nachteile:
Alle Methoden, die Schnittstellen implementieren, sind mit dem korrekten Receiver deklariert. Schnittstellen werden nicht dort verwendet, wo es nicht nötig ist (konkreter Typ, wo möglich; Polymorphismus, wo nötig).
Vorteile:
Nachteile: