Interfaces and pointer receivers

gopher picture gopher · Aug 12, 2017 · Viewed 9.7k times · Source

I am newbie gopher and trying to get my head around the pointer receivers and interfaces.

type Foo interface {
    foo()
}
type Bar struct {}
func (b *Bar) foo() {}

based on the above definitions..

--- Allowed ---------
b := Bar{}
b.foo()

--- Not allowed ----- 

var foo Foo = Bar{}

Get compiler error: cannot use Bar literal (type Bar) as type Foo in assignment: Bar does not implement Foo (foo method has pointer receiver)

I understand that compiler is doing some pointer conversion and de-referencing on our behalf in the first scenario. Why doesn't it do the same thing in the second scenario ?

Answer

Naveen Ramanathan picture Naveen Ramanathan · Aug 12, 2017

Short answer var foo Foo = Bar{} is not working because the concrete value stored in an interface is not addressable.

Longer Version

Please read https://github.com/golang/go/wiki/MethodSets

It is legal to call a pointer-valued method on anything that is already a pointer or whose address can be taken. It is legal to call a value method on anything which is a value or whose value can be dereferenced.

With respect to the above explanation, your code

b := Bar{}
b.foo()

works because b is addressable.

The concrete value stored in an interface is not addressable. Therefore, when you call a method on an interface, it must either have an identical receiver type or it must be directly discernible from the concrete type: pointer- and value-receiver methods can be called with pointers and values respectively, as you would expect. Value-receiver methods can be called with pointer values because they can be dereferenced first. Pointer-receiver methods cannot be called with values, however, because the value stored inside an interface has no address. When assigning a value to an interface, the compiler ensures that all possible interface methods can actually be called on that value, and thus trying to make an improper assignment will fail on compilation.

According to the above explanation the concrete value stored in an interface is not addressable and hence the code,

var foo Foo = Bar{}

will not work because the concrete value stored in an interface, in this case Bar{}, is not addressable.