151
votes

I'm just working through the Go tour, and I'm confused about pointers and interfaces. Why doesn't this Go code compile?

package main

type Interface interface {}

type Struct struct {}

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

    _, _ = pi, ps
}

i.e. if Struct is an Interface, why wouldn't a *Struct be a *Interface?

The error message I get is:

prog.go:10: cannot use ps (type *Struct) as type *Interface in assignment:
        *Interface is pointer to interface, not interface
4
it looks like the interfaces could behaves like implicit pointers... - Victor
may i suggest to enrich your playground with 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 } and make your own conclussions - Victor

4 Answers

204
votes

When you have a struct implementing an interface, a pointer to that struct implements automatically that interface too. That's why you never have *SomeInterface in the prototype of functions, as this wouldn't add anything to SomeInterface, and you don't need such a type in variable declaration (see this related question).

An interface value isn't the value of the concrete struct (as it has a variable size, this wouldn't be possible), but it's a kind of pointer (to be more precise a pointer to the struct and a pointer to the type). Russ Cox describes it exactly here :

Interface values are represented as a two-word pair giving a pointer to information about the type stored in the interface and a pointer to the associated data.

enter image description here

This is why Interface, and not *Interface is the correct type to hold a pointer to a struct implementing Interface.

So you must simply use

var pi Interface
8
votes

This is perhaps what you meant:

package main

type Interface interface{}

type Struct struct{}

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

        _, _ = pi, ps
}

Compiles OK. See also here.

0
votes

Here's a very simple way of assigning a struct to an 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

0
votes

Im using the following way of interface{} while im just consuming eventsI interface{} as arguments, im still able to send a Struct Pointers as you can see below.

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)

Now inside storyboard.go file Create function

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
}

As you can see above the Storyboard.go is consuming just Events []interface{} but in-fact Im sending is a Struct pointer and it works fine.

another more example here