10

I have the following code:

package main


type MyInterface interface {
    Test()
}

type MyType struct {

}
func (m MyType) Test(){}

func AcceptInterface(i *MyInterface){
}

func main() {

    object := &MyType{}
    AcceptInterface(object)
}

I was expecting this to work, because MyType implements MyInterface, but I get:

cannot use object (type *MyType) as type *MyInterface in argument to AcceptInterface: *MyInterface is pointer to interface, not interface

I tried doing type assertion: object.(MyInterface), but that doesn't work either.

How can I accomplish this?

lucaswxp
  • 2,031
  • 5
  • 23
  • 34

3 Answers3

15

As the error says,

cannot use object (type *MyType) as type *MyInterface in argument to AcceptInterface: *MyInterface is pointer to interface, not interface

This means that it is expecting an interface value, not a pointer.

If you change the pointers to values in your code (by removing the & and *), the program will run with no errors:

package main


type MyInterface interface {
    Test()
}

type MyType struct {

}
func (m MyType) Test(){}

func AcceptInterface(i MyInterface){
}

func main() {

    object := MyType{}
    AcceptInterface(object)
}

Play it

Edit 1

If you still want to use a pointer as an argument, there are two important parts of the Go language to note

  1. From the Go Spec on what exacly is a variable that fits an instance:

    A variable of interface type can store a value of any type with a method set that is any superset of the interface.

  2. From the Go Spec on what pointers being automatically dereferenced:

    As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv [and] as with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.

Those two points are important, because when combined they explain that pointers to variables can still fit instances. This is because the pointer's method set is automatically dereferenced by the Go compiler (and since the variable it is referencing can fit an instance, the pointer can, too)!

In action, this means that in order to see if a pointer fits an instance, you have to declare the instance as a value and the pointer as a pointer.

If you run this code:

package main

type MyInterface interface {
    Test()
}

type MyType struct {
}

func (m MyType) Test() {}

func AcceptInterface(i MyInterface) {
}

func main() {
    object := &MyType{}
    AcceptInterface(object)
}

Play it

you will see that there are no errors! Notice how there is an & in the object declaration, but no * in the i declaration?

Community
  • 1
  • 1
Marco
  • 2,004
  • 15
  • 24
  • That works, thanks! But I don't quite understand why I can't pass pointers, does that means that interfaces are "first class citizens", I can have pointers to actual interfaces instead of a struct? Don't know if that makes sense. – lucaswxp Jan 17 '17 at 03:14
  • @lucaswxp I edited my answer with a way to pass in pointers; hopefully it helps you! – Marco Jan 17 '17 at 04:18
  • @lucaswxp The main issue in your code, as also pointed by @JimB, is that your `AcceptInterface` expects *pointer* to an interface argument. In general, you should just use interface argument. If it's fixed, you can pass struct pointers into it. – exavolt Jan 17 '17 at 04:41
  • I think the more interesting question (to me) is why we cannot have an interface pointer as a parameter? What does an interface pointer mean? – Alaska Oct 14 '21 at 20:32
0
type MyInterface interface {
    Test()
}

type MyType struct {

}
func (m MyType) Test(){}

Note: it means that MyType implemts the interface MyInterface, not MyType*.

You can use:

func (m *MyType) Test(){}  //Notice here

func AcceptInterface(i *MyInterface){
}

func main() {

    object := &MyType{}
    AcceptInterface(object)
}
BlackMamba
  • 10,054
  • 7
  • 44
  • 67
  • From the spec: `The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T`. You can use a pointer or struct value interchangeably with a value receiver. – JimB Jan 17 '17 at 14:19
0

Use explicit typing if you want to pass a pointer to interface:

func main() {
    var object MyInterface = MyType{}
    AcceptInterface(&object)
}

I would not recommend using pointer interfaces as you would need to write code like (*i).Test() to call the interface pointer methods. The compiler do auto dereferencing for struct pointers, not so for interface pointers.

Ankur
  • 33,367
  • 2
  • 46
  • 72