2015-11-26 14 views
12

Ich habe diesen Beispiel-CodeGolang Methode mit Zeigern Empfänger

package main 

import (
    "fmt" 
) 

type IFace interface { 
    SetSomeField(newValue string) 
    GetSomeField() string 
} 

type Implementation struct { 
    someField string 
} 

func (i Implementation) GetSomeField() string { 
    return i.someField 
} 

func (i Implementation) SetSomeField(newValue string) { 
    i.someField = newValue 
} 

func Create() IFace { 
    obj := Implementation{someField: "Hello"} 
    return obj // <= Offending line 
} 

func main() { 
    a := Create() 
    a.SetSomeField("World") 
    fmt.Println(a.GetSomeField()) 
} 

SetSomeField nicht wie erwartet funktioniert, weil sein Empfänger nicht von Zeigertyp ist.

Wenn ich die Methode auf einen Zeiger Empfänger zu ändern, was ich erwarten würde, zu arbeiten, sieht es wie folgt aus:

func (i *Implementation) SetSomeField(newValue string) { ... 

Kompilieren dies zu folgendem Fehler führt:

prog.go:26: cannot use obj (type Implementation) as type IFace in return argument: 
Implementation does not implement IFace (GetSomeField method has pointer receiver) 

Wie kann Ich habe die struct implementieren die Schnittstelle und die Methode SetSomeField den Wert der tatsächlichen Instanz ändern, ohne eine Kopie zu erstellen?

Hier ist ein hackable Schnipsel: https://play.golang.org/p/ghW0mk0IuU

ich diese Frage schon In go (golang), how can you cast an interface pointer into a struct pointer? gesehen habe, aber ich kann nicht sehen, wie es zu diesem Beispiel verwendet ist.

+0

Beide Methoden erfordern Zeiger Empfänger, sonst sind Sie nur einen Teil der Schnittstelle implementiert. – elithrar

Antwort

16

Ihr Zeiger auf die Struktur sollte die Schnittstelle implementieren. Auf diese Weise können Sie seine Felder ändern.

Blick darauf, wie ich Ihren Code geändert, es arbeiten zu machen, wie Sie erwarten:

package main 

import (
    "fmt" 
) 

type IFace interface { 
    SetSomeField(newValue string) 
    GetSomeField() string 
} 

type Implementation struct { 
    someField string 
}  

func (i *Implementation) GetSomeField() string { 
    return i.someField 
} 

func (i *Implementation) SetSomeField(newValue string) { 
    i.someField = newValue 
} 

func Create() *Implementation { 
    return &Implementation{someField: "Hello"} 
} 

func main() { 
    var a IFace 
    a = Create() 
    a.SetSomeField("World") 
    fmt.Println(a.GetSomeField()) 
} 
+0

Bah das war es. Es gab noch eine andere Methode, die nicht als Zeigerempfänger deklariert wurde. Vielen Dank – Atmocreations

9

Die einfache Antwort ist, dass Sie nicht in der Lage sein werden, die Struktur Ihre Schnittstelle implementieren zu lassen, während Sie SetSomeField arbeiten, wie Sie wollen.

Allerdings wird ein Zeiger auf die Struktur die Schnittstelle implementieren, also sollte die Create Methode ändern, um return &obj tun Dinge funktionieren zu tun.

Das zugrunde liegende Problem ist, dass Ihre modifizierte SetSomeField-Methode nicht mehr im Methodensatz Implementation ist. Während der Typ *Implementation die Nicht-Zeiger-Empfängermethoden erbt, ist das Umgekehrte nicht wahr.

Der Grund dafür hängt mit der Art und Weise zusammen, wie Schnittstellenvariablen angegeben werden: Die einzige Möglichkeit, auf den in einer Schnittstellenvariablen gespeicherten dynamischen Wert zuzugreifen, besteht darin, ihn zu kopieren. Als Beispiel vorstellen, dass die folgenden:

var impl Implementation 
var iface IFace = &impl 

In diesem Fall wird ein Aufruf an iface.SetSomeField funktioniert, weil es den Zeiger zu verwenden, da der Empfänger in dem Methodenaufruf kopieren. Wenn wir eine Struktur direkt in der Schnittstellenvariablen speichern würden, müssten wir einen Zeiger auf diese Struktur erstellen, um den Methodenaufruf abzuschließen. Sobald ein solcher Zeiger erstellt wurde, ist es möglich, auf den dynamischen Wert der Schnittstellenvariablen zuzugreifen (und möglicherweise zu modifizieren), ohne ihn zu kopieren.