150 votes

" <type> est un pointeur sur l'interface, pas sur l'interface "confusion

Chers développeurs,

J'ai ce problème qui semble un peu bizarre pour moi. Regardez 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 paquet, 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 moment de l'exécution n'accepte pas la ligne, parce que

"ne peut pas utiliser fieldfilter (type *coreinterfaces.FieldFilter) type de *coreinterfaces.FilterInterface en argument à fieldint.AddFilter: *coreinterfaces.FilterInterface est pointeur vers l'interface, pas d'interface"

Cependant, lors de la modification du code:

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. Quand on regarde les autres posts de blog et de dépassement de pile discussions exactement le même problème (par exemple - Ce, ou C') le premier extrait qui soulève cette exception devrait fonctionner, parce que les deux fieldfilter et field-map sont initialisés comme des pointeurs vers des interfaces, plutôt que de la valeur des interfaces. Je n'ai pas été capable d'envelopper ma tête autour de ce qui se passe réellement ici que j'ai besoin de changement dans l'ordre pour moi de ne pas déclarer un FieldInterface et affecter la mise en œuvre de cette interface. Il doit y avoir un moyen élégant pour ce faire.

213voto

Kaedys Points 4092

Si vous êtes confus deux concepts ici. Un pointeur vers une struct et un pointeur vers une interface ne sont pas les mêmes. Une interface peut stocker une structure directement ou un pointeur vers une struct. Dans ce dernier cas, on continue à utiliser directement l'interface, pas un pointeur vers l'interface. Par exemple:

type Fooer interface {
    Foo()
}

type Foo struct{}

func (f Foo) Foo() {}

func main() {
    var f1 Foo
    var f2 *Foo = &Foo{}

    DoFoo(f1)
    DoFoo(f2)
}

func DoFoo(f Fooer) {
    fmt.Printf("[%T] %+v\n", f, f)
}

Sortie:

[main.Foo] {}
[*main.Foo] &{}

https://play.golang.org/p/BGV9d1-IRW

Dans les deux cas, l' f variable DoFoo est juste une interface, pas un pointeur vers une interface. Toutefois, lorsque le stockage des f2, l'interface est titulaire d' un pointeur à un Foo de la structure.

Des pointeurs vers les interfaces sont presque jamais utile. En fait, l'Aller exécution a été spécialement changé quelques versions ne sont plus automatiquement de déréférencement de pointeurs d'interface (comme c'est le cas pour la structure de pointeurs), afin de décourager leur utilisation. Dans l'écrasante majorité des cas, un pointeur vers une interface reflète un manque de compréhension de la façon dont les interfaces sont censés travailler.

Cependant, il y a une limitation sur les interfaces. Si vous passez une structure directement dans une interface, seule la valeur des méthodes de ce type (c'est à dire. func (f Foo) Foo(), pas func (f *Foo) Foo()) peut être utilisée pour réaliser l'interface. C'est parce que vous êtes stockage d'une copie de la structure d'origine de l'interface, de sorte que le pointeur de méthodes pourraient avoir des effets inattendus (ie. incapables de modifier la structure d'origine). Ainsi, la valeur par défaut de la règle de base est de stocker des pointeurs vers des structures dans les interfaces, sauf s'il y a une raison impérieuse de ne pas.

Spécifiquement avec votre code, si vous modifiez le AddFilter fonction de signature à:

func (fp *FilterMap) AddFilter(f FilterInterface) uuid.UUID

Et le GetFilterByID signature à:

func (fp *FilterMap) GetFilterByID(i uuid.UUID) FilterInterface

Votre code fonctionne comme prévu. fieldfilter est de type *FieldFilter, ce qui capable de réaliser l' FilterInterface type d'interface, et donc AddFilter l'acceptent.

Voici un couple de bonnes références pour la compréhension de la façon dont les méthodes, les types et les interfaces de travail et les intégrer les uns avec les autres dans le jeu de Go:

11voto

Dan Farrell Points 1558
GetFilterByID(i uuid.UUID) *FilterInterface

Quand je reçois ce message d'erreur, c'est généralement parce que je suis en spécifiant un pointeur vers une interface au lieu d'une interface ( qui seront effectivement un pointeur de ma structure qui répond à l'interface ).

Il y a une utilisation valide pour *interface {...}, mais le plus souvent j'ai juste pense "c'est un pointeur" au lieu de "c'est une interface qui se trouve être un pointeur dans le code que j'ai écris'

Juste le jeter là-bas parce que l'on a accepté la réponse, si détaillée, ne m'aide pas à résoudre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X