Why can't I assign a *Struct to an *Interface?
GoGo Problem Overview
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
Go Solutions
Solution 1 - Go
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.
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
Solution 2 - Go
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.
Solution 3 - Go
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
}
Solution 4 - Go
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