Empfänger und Schnittstelle

Methoden mit Wertempfängern können sowohl mit Werten als auch mit Zeigern aufgerufen werden.

Methoden mit Zeigerempfängern können nur mit Zeigern oder adressierbaren Werten aufgerufen werden.

Beispiel:

type S struct {
  data string
}

func (s S) Read() string {
  return s.data
}

func (s *S) Write(str string) {
  s.data = str
}

sVals := map[int]S{1: {"A"}}

// Sie können Read nur mit einem Wert aufrufen
sVals[1].Read()

// Dies wird nicht kompilieren:
// sVals[1].Write("test")

sPtrs := map[int]*S{1: {"A"}}

// Sowohl Read als auch Write Methoden können mit einem Zeiger aufgerufen werden
sPtrs[1].Read()
sPtrs[1].Write("test")

Ebenso kann eine Methode, auch wenn sie einen Wertempfänger hat, eine Schnittstelle mithilfe eines Zeigerempfängers erfüllen.

type F interface {
  f()
}

type S1 struct{}

func (s S1) f() {}

type S2 struct{}

func (s *S2) f() {}

s1Val := S1{}
s1Ptr := &S1{}
s2Val := S2{}
s2Ptr := &S2{}

var i F
i = s1Val
i = s1Ptr
i = s2Ptr

// Der folgende Code wird nicht kompilieren, da s2Val ein Wert ist und die Methode f von S2 keinen Wertempfänger hat
// i = s2Val

Effective Go enthält ausgezeichnete Erklärungen zu Zeigern vs. Werten.

Zusätzliche Hinweise:

  • Ein Typ kann einen Methodensatz mit Wertempfängern und einen Methodensatz mit Zeigerempfängern haben.
    • Der Methodensatz mit Wertempfängern ist ein Untermenge des Methodensatzes mit Zeigerempfängern, aber nicht umgekehrt.
  • Regeln
    • Wertobjekte können nur den Methodensatz mit Wertempfängern verwenden.
    • Zeigerobjekte können den Methodensatz mit Wertempfängern + den Methodensatz mit Zeigerempfängern verwenden.
  • Schnittstellenanpassung (oder Implementierung)
    • Der Typ passt zur Schnittstelle, wenn er alle Methoden der Schnittstelle implementiert.
    • Genauer gesagt, passt entweder der Wertmethodensatz des Typs zur Schnittstelle oder der Zeigermethodensatz passt zur Schnittstelle.

Es gibt zwei spezifische Arten des Anpassens:

  • Wertmethodensatz passt zur Schnittstelle
    • Es ist in Ordnung, einem Wert oder einem Zeigerobjekt eine Schnittstellenvariable zuzuweisen, da beide den Wertmethodensatz enthalten.
  • Zeigermethodensatz passt zur Schnittstelle
    • Nur ein Zeigerobjekt kann einer Schnittstellenvariable zugewiesen werden, da nur der Zeigermethodensatz zur Schnittstelle passt.
    • Wenn einem Wertobjekt eine Schnittstellenvariable zugewiesen wird, wird während der Kompilierung ein Mechanismus zur Überprüfung der Schnittstellenaktualität ausgelöst.

Warum i = s2Val einen Fehler auslöst, liegt daran, dass der Wertmethodensatz und die Schnittstelle nicht übereinstimmen.