161 votes

Pourquoi ne puis-je pas affecter une *Struct à une *Interface ?

Je suis juste en train de travailler sur le Allez-y et je suis confus à propos des pointeurs et des interfaces. Pourquoi ce code Go ne compile-t-il pas ?

package main

type Interface interface {}

type Struct struct {}

func main() {
    var ps *Struct
    var pi *Interface
    pi = ps

    _, _ = pi, ps
}

c'est-à-dire que si Struct est un Interface pourquoi un *Struct être un *Interface ?

Le message d'erreur que je reçois est le suivant :

prog.go:10: cannot use ps (type *Struct) as type *Interface in assignment:
        *Interface is pointer to interface, not interface

1 votes

0 votes

Il semble que les interfaces pourraient se comporter comme des pointeurs implicites...

0 votes

func main() { var ps *Struct = new(Struct) var pi *Interface var i Interface i = ps pi = &i fmt.Printf("%v, %v, %v\n", *ps, pi, &i) i = *ps fmt.Printf("%v, %v, %v\n", *ps, pi, i) _, _, _ = i, pi, ps } et tirez vos propres conclusions

217voto

dystroy Points 145126

Lorsque vous avez une structure implémentant une interface, un pointeur vers cette structure implémente automatiquement cette interface également. C'est pourquoi vous n'avez jamais *SomeInterface dans le prototype des fonctions, car cela n'ajouterait rien à SomeInterface et vous n'avez pas besoin d'un tel type dans la déclaration d'une variable (cf. cette question connexe ).

Une valeur d'interface n'est pas la valeur de la structure concrète (comme elle a une taille variable, cela ne serait pas possible), mais c'est une sorte de pointeur (pour être plus précis, un pointeur vers la structure et un pointeur vers le type). Russ Cox le décrit exactement ici :

Les valeurs d'interface sont représentées sous la forme d'une paire de deux mots donnant un pointeur informations sur le type stocké dans l'interface et un pointeur sur les données les données associées.

enter image description here

C'est pourquoi Interface et non *Interface est le type correct pour contenir un pointeur vers une structure qui implémente Interface .

Vous devez donc simplement utiliser

var pi Interface

9 votes

OK, je pense que ça a du sens pour moi. Je me demande simplement pourquoi (dans ce cas), ce n'est pas simplement une erreur de compilation de dire var pi *Interface .

1 votes

Je suis entré dans les détails pour l'expliquer. Voir l'édition. Je suggère la lecture de l'article de Russ Cox dont je donne le lien.

0 votes

@SimonNickerson : les pointeurs vers différents types ne sont pas interchangeables. S'ils l'étaient, vous pourriez utiliser le pointeur de l'interface pour écraser la chose pointée avec n'importe quelle valeur de n'importe quel type qui implémente l'interface, ce qui n'est évidemment pas bon.

10voto

zzzz Points 23017

C'est peut-être ce que vous vouliez dire :

package main

type Interface interface{}

type Struct struct{}

func main() {
        var ps *Struct
        var pi *Interface
        pi = new(Interface)
        *pi = ps

        _, _ = pi, ps
}

Compile OK. Voir aussi ici .

1 votes

Ceci devrait être accepté, l'autre ne répond pas vraiment à la question.

0voto

Miguel Mota Points 14005

Voici une façon très simple d'assigner un struct à une interface :

package main

type Interface interface{}

type Struct struct{}

func main() {
    ps := new(Struct)
    pi := Interface(ps)

    _, _ = pi, ps
}

https://play.golang.org/p/BRTaTA5AG0S

0voto

STEEL Points 649

J'utilise la méthode suivante interface{} alors que je ne fais que consommer eventsI interface{} comme arguments, je suis toujours capable d'envoyer un pointeur de structure comme vous pouvez le voir ci-dessous.

func Wait(seconds float64) *WaitEvent {
    return WaitEventCreate(seconds)
}

main.go

var introScene = []interface{}{
        storyboard.Wait(5),
        storyboard.Wait(2),
    }

    var storyboardI = storyboard.Create(stack, introScene)
    stack.Push(&storyboardI)

Maintenant à l'intérieur storyboard.go fichier Créer une fonction

type Storyboard struct {
    Stack  *gui.StateStack
    Events []interface{} //always keep as last args
}

func Create(stack *gui.StateStack, eventsI interface{}) Storyboard {
    sb := Storyboard{
        Stack: stack,
    }

    if eventsI != nil {
        events := reflect.ValueOf(eventsI)
        if events.Len() > 0 {
            sb.Events = make([]interface{}, events.Len())
            for i := 0; i < events.Len(); i++ {
                sb.Events[i] = events.Index(i).Interface()
            }
        }
    }

    return sb
}

Comme vous pouvez le voir ci-dessus le Storyboard.go consomme juste Events []interface{} mais en fait, j'envoie un pointeur structurel et cela fonctionne bien.

un autre exemple de plus ici

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