164

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
Simon Nickerson
  • 42,159
  • 20
  • 102
  • 127
  • 1
    See also http://stackoverflow.com/q/20874798/260805 – Ztyx Jan 02 '14 at 07:48
  • it looks like the interfaces could behaves like implicit pointers... – Victor Apr 06 '17 at 14:25
  • 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 Apr 06 '17 at 14:44

4 Answers4

223

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
Community
  • 1
  • 1
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 9
    OK, I think that makes sense to me. I'm just wondering why (in that case), it's not simply a compile time error to say `var pi *Interface`. – Simon Nickerson Nov 22 '12 at 11:34
  • 1
    I went into more details to explain it. See edit. I suggest the reading of the Russ Cox's article I link to. – Denys Séguret Nov 22 '12 at 11:41
  • @SimonNickerson: pointers to different types are not interchangeable. If they were, you could use the interface pointer to overwrite the thing pointed to with any value of any type that implements the interface, which is obviously not good – newacct Nov 23 '12 at 00:18
  • 1
    This just helped me make sense of pointers in a way I was *never* able to do in C or C++ ... thank you so much for this elegant and simple explanation :-) – mindplay.dk Dec 27 '13 at 14:52
  • 3
    Alright, I still don't get why `*SomeInterface` isn't simply a compile error? – sazary Nov 15 '16 at 13:48
  • thanks for the explanation... although i don't get what is the "prototype of functions"? – Victor Apr 06 '17 at 14:13
  • 2
    @charneykaye You are not entirely correct here. You never have *SomeInterface **when declaring an interface variable** or **when returning an interface type as part of a function declaration**. However **you can have *SomeInterface within a function's parameters**. – Andi Dec 06 '17 at 14:08
  • so tecnically interface{} is a **wrapper** (i guess we should use that word for transmiting the idea at a glance..., humble suggestion folks) – Victor May 23 '18 at 13:26
  • Turns out that hiding the pointer was not such a hot language design idea after all, as you still need to be aware it exists, just like it exists in slices and maps. – Tom Nov 09 '21 at 21:23
10

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.

zzzz
  • 87,403
  • 16
  • 175
  • 139
0

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

Miguel Mota
  • 20,135
  • 5
  • 45
  • 64
0

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

STEEL
  • 8,955
  • 9
  • 67
  • 89