Why can't I assign a *Struct to an *Interface?

Go

Go 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.

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

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
}

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSimon NickersonView Question on Stackoverflow
Solution 1 - GoDenys SéguretView Answer on Stackoverflow
Solution 2 - GozzzzView Answer on Stackoverflow
Solution 3 - GoMiguel MotaView Answer on Stackoverflow
Solution 4 - GoSTEELView Answer on Stackoverflow