Chers collègues développeurs,
J'ai ce problème qui me semble un peu étrange. Jetez un œil à cet extrait de code:
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
}
Sur un autre package, j'ai le code suivant:
func DoFilter() {
fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
filtermap := &coreinterfaces.FilterMap{}
_ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}
Le run-time n'acceptera pas la ligne mentionnée car
"ne peut pas utiliser fieldfilter (type * coreinterfaces.FieldFilter) comme type * coreinterfaces.FilterInterface dans l'argument de fieldint.AddFilter: * coreinterfaces.FilterInterface est un pointeur vers l'interface, pas l'interface"
Cependant, lorsque vous modifiez le code en:
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)
}
Tout va bien et lors du débogage de l'application, il semble vraiment inclure
Je suis un peu confus sur ce sujet. Lorsque vous consultez d'autres articles de blog et les threads de débordement de pile discutant exactement du même problème (par exemple - Ceci ou Ceci ), le premier extrait de code qui lève cette exception devrait fonctionner, car fieldfilter et fieldmap sont initialisés en tant que pointeurs vers des interfaces, plutôt que comme valeur de les interfaces. Je n'ai pas été en mesure de comprendre ce qui se passe réellement ici et que je dois changer pour ne pas déclarer une FieldInterface et affecter l'implémentation de cette interface. Il doit y avoir une manière élégante de faire cela.
* FilterInterface
àFilterInterface
La ligne_ = filtermap.AddFilter(fieldfilter)
lève maintenant ceci: impossible d'utiliser fieldfilter (type coreinterfaces.FieldFilter) comme type coreinterfaces.FilterInterface en argument en filtermap.AddFilter: coreinterfaces.FieldFilter n'implémente pas coreinterfaces.FilterInterface (la méthode Filter a un récepteur de pointeur) Cependant lors du changement de ligne à_ = filtermap.AddFilter(&fieldfilter)
cela fonctionne. Que se passe t-il ici? pourquoi donc?* FilterInterface
en une structure qui implémente cette interface, cela rompt l'idée de passer des interfaces aux fonctions. Ce que je voulais accomplir, ce n'est pas d'être lié à la structure que je passais, mais plutôt à toute structure qui implémente l'interface que je suis intéressé à utiliser. Y a-t-il des changements de code que vous pensez être plus efficaces ou conformes aux normes que je dois faire? Je serai heureux d'utiliser certains services de révision de code :)Réponses:
Vous confondez donc deux concepts ici. Un pointeur vers une structure et un pointeur vers une interface ne sont pas les mêmes. Une interface peut stocker directement une structure ou un pointeur vers une structure. Dans ce dernier cas, vous utilisez toujours simplement l'interface directement, pas un pointeur vers l'interface. Par exemple:
Production:
https://play.golang.org/p/I7H_pv5H3Xl
Dans les deux cas, la
f
variable inDoFoo
est simplement une interface, pas un pointeur vers une interface. Cependant, lors du stockagef2
, l'interface contient un pointeur vers uneFoo
structure.Les pointeurs vers les interfaces ne sont presque jamais utiles. En fait, le runtime Go a été spécifiquement modifié quelques versions pour ne plus déréférencer automatiquement les pointeurs d'interface (comme c'est le cas pour les pointeurs de structure), afin de décourager leur utilisation. Dans la très grande majorité des cas, un pointeur vers une interface reflète un malentendu sur la façon dont les interfaces sont censées fonctionner.
Cependant, il existe une limitation sur les interfaces. Si vous passez une structure directement dans une interface, seules les méthodes de valeur de ce type (c'est-à-dire
func (f Foo) Dummy()
nonfunc (f *Foo) Dummy()
) peuvent être utilisées pour remplir l'interface. C'est parce que vous stockez une copie de la structure originale dans l'interface, donc les méthodes de pointeur auraient des effets inattendus (c'est-à-dire incapables de modifier la structure originale). Ainsi, la règle empirique par défaut est de stocker des pointeurs vers des structures dans des interfaces , à moins qu'il n'y ait une raison impérieuse de ne pas le faire.Plus précisément avec votre code, si vous modifiez la signature de la fonction AddFilter en:
Et la signature GetFilterByID pour:
Votre code fonctionnera comme prévu.
fieldfilter
est de type*FieldFilter
, qui remplit leFilterInterface
type d'interface, et doncAddFilter
l'acceptera.Voici quelques bonnes références pour comprendre comment les méthodes, les types et les interfaces fonctionnent et s'intègrent les uns aux autres dans Go:
la source
Lorsque j'obtiens cette erreur, c'est généralement parce que je spécifie un pointeur vers une interface au lieu d'une interface (qui sera en fait un pointeur vers ma structure qui remplit l'interface).
Il y a une utilisation valide pour * interface {...} mais le plus souvent je pense juste "ceci est un pointeur" au lieu de "ceci est une interface qui se trouve être un pointeur dans le code que j'écris"
Je l'ai simplement lancé parce que la réponse acceptée, bien que détaillée, ne m'a pas aidé à résoudre le problème.
la source