Liebe Entwicklerkollegen,
Ich habe dieses Problem, das mir etwas komisch vorkommt. Schauen Sie sich diesen Codeausschnitt an:
package coreinterfaces
type FilterInterface interface {
Filter(s *string) bool
}
type FieldFilter struct {
Key string
Val string
}
func (ff *FieldFilter) Filter(s *string) bool {
// Some code
}
type FilterMapInterface interface {
AddFilter(f *FilterInterface) uuid.UUID
RemoveFilter(i uuid.UUID)
GetFilterByID(i uuid.UUID) *FilterInterface
}
type FilterMap struct {
mutex sync.Mutex
Filters map[uuid.UUID]FilterInterface
}
func (fp *FilterMap) AddFilter(f *FilterInterface) uuid.UUID {
// Some code
}
func (fp *FilterMap) RemoveFilter(i uuid.UUID) {
// Some code
}
func (fp *FilterMap) GetFilterByID(i uuid.UUID) *FilterInterface {
// Some code
}
Auf einem anderen Paket habe ich den folgenden Code:
func DoFilter() {
fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
filtermap := &coreinterfaces.FilterMap{}
_ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}
Die Laufzeit akzeptiert die erwähnte Zeile nicht, weil
"Feldfilter (Typ * coreinterfaces.FieldFilter) kann nicht als Typ * coreinterfaces.FilterInterface im Argument zu fieldint.AddFilter verwendet werden: * coreinterfaces.FilterInterface ist Zeiger auf Schnittstelle, nicht Schnittstelle"
Wenn Sie den Code jedoch ändern in:
func DoBid() error {
bs := string(b)
var ifilterfield coreinterfaces.FilterInterface
fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
ifilterfield = fieldfilter
filtermap := &coreinterfaces.FilterMap{}
_ = filtermap.AddFilter(&ifilterfield)
}
Alles ist in Ordnung und beim Debuggen der Anwendung scheint es wirklich zu enthalten
Ich bin etwas verwirrt über dieses Thema. Wenn Sie sich andere Blog-Beiträge und Stapelüberlauf-Threads ansehen, in denen genau dasselbe Problem behandelt wird (z. B. Dies oder Dies ), sollte das erste Snippet funktionieren, das diese Ausnahme auslöst, da sowohl Feldfilter als auch Feldzuordnung als Zeiger auf Schnittstellen und nicht als Wert von initialisiert werden Schnittstellen. Ich konnte mich nicht mit dem befassen, was hier tatsächlich passiert und was ich ändern muss, damit ich kein FieldInterface deklariere und die Implementierung für diese Schnittstelle zuweise. Es muss einen eleganten Weg geben, dies zu tun.
* FilterInterface
aufFilterInterface
die Linie_ = filtermap.AddFilter(fieldfilter)
jetzt wirft dies: nicht verwenden kann fieldfilter (Typ coreinterfaces.FieldFilter) als Typ coreinterfaces.FilterInterface in Argumente filtermap.AddFilter: coreinterfaces.FieldFilter nicht implementiert coreinterfaces.FilterInterface (Filter - Methode hat Empfänger Zeiger) jedoch , wenn der Wechsel Linie dazu_ = filtermap.AddFilter(&fieldfilter)
funktioniert. was geschieht hier? warum ist das so?* FilterInterface
in eine Struktur, die diese Schnittstelle implementiert, wird die Idee, Schnittstellen an Funktionen zu übergeben, zunichte gemacht. Was ich erreichen wollte, ist nicht an die Struktur gebunden zu sein, die ich übergeben habe, sondern an jede Struktur, die die Schnittstelle implementiert, die ich verwenden möchte . Gibt es Codeänderungen, die Ihrer Meinung nach effizienter sind oder den von mir zu erwartenden Standards entsprechen? Ich werde froh sein, einigeAntworten:
Sie verwechseln hier also zwei Konzepte. Ein Zeiger auf eine Struktur und ein Zeiger auf eine Schnittstelle sind nicht identisch. Eine Schnittstelle kann entweder eine Struktur direkt oder einen Zeiger auf eine Struktur speichern . Im letzteren Fall verwenden Sie immer noch nur die Schnittstelle direkt und keinen Zeiger auf die Schnittstelle. Beispielsweise:
Ausgabe:
https://play.golang.org/p/I7H_pv5H3Xl
In beiden Fällen ist die
f
Variable inDoFoo
nur eine Schnittstelle, kein Zeiger auf eine Schnittstelle. Wenn jedoch die Speicherungf2
, die Schnittstelle enthält einen Zeiger auf eineFoo
Struktur.Zeiger auf Schnittstellen sind fast nie nützlich. Tatsächlich wurde die Go-Laufzeit einige Versionen zurück geändert, um Schnittstellenzeiger nicht mehr automatisch zu dereferenzieren (wie dies bei Strukturzeigern der Fall ist), um deren Verwendung zu verhindern. In den allermeisten Fällen spiegelt ein Zeiger auf eine Schnittstelle ein Missverständnis darüber wider, wie Schnittstellen funktionieren sollen.
Es gibt jedoch eine Einschränkung für Schnittstellen. Wenn Sie eine Struktur direkt an eine Schnittstelle übergeben, können nur Wertmethoden dieses Typs (dh
func (f Foo) Dummy()
nichtfunc (f *Foo) Dummy()
) verwendet werden, um die Schnittstelle zu erfüllen. Dies liegt daran, dass Sie eine Kopie der ursprünglichen Struktur in der Benutzeroberfläche speichern, sodass Zeigermethoden unerwartete Auswirkungen haben (dh die ursprüngliche Struktur können nicht geändert werden). Die Standard-Faustregel lautet daher , Zeiger auf Strukturen in Schnittstellen zu speichern , es sei denn, es gibt einen zwingenden Grund, dies nicht zu tun.Speziell mit Ihrem Code, wenn Sie die Signatur der AddFilter-Funktion in Folgendes ändern:
Und die GetFilterByID-Signatur für:
Ihr Code funktioniert wie erwartet.
fieldfilter
ist vom Typ*FieldFilter
, der denFilterInterface
Schnittstellentyp vollständig ausfüllt und ihn somitAddFilter
akzeptiert.Im Folgenden finden Sie einige gute Referenzen zum Verständnis der Funktionsweise und Integration von Methoden, Typen und Schnittstellen in Go:
quelle
Wenn ich diesen Fehler erhalte, liegt dies normalerweise daran, dass ich anstelle einer Schnittstelle einen Zeiger auf eine Schnittstelle gebe (dies ist tatsächlich ein Zeiger auf meine Struktur, die die Schnittstelle erfüllt).
Es gibt eine gültige Verwendung für * interface {...}, aber häufiger denke ich nur, dass dies ein Zeiger ist, anstatt dass dies eine Schnittstelle ist, die zufällig ein Zeiger in dem Code ist, den ich schreibe.
Ich habe es einfach rausgeworfen, weil die akzeptierte Antwort, obwohl detailliert, mir nicht bei der Fehlerbehebung geholfen hat.
quelle