Kenny Worden
Kenny Worden

Reputation: 4572

Passing an interface pointer in a function parameter

I am trying to understand Golang (1.12) interfaces. I found out that interface pointers must be explicitly dereferenced, unlike structs:

import "fmt"

// A simple interface with one function
type myinter interface {
    hello()
}

// Implement myinter
type mystruct struct {}

func (mystruct) hello() {
    fmt.Println("I am T!")
}

// Some function that calls the hello function as defined by myinter
func callHello(i *myinter) {   
    i.hello()  // <- cannot resolve reference 'hello'
}

func main() {
    newMystruct := &mystruct{}
    callHello(newMystruct)
}

Here, my callHello function cannot resolve the reference to my hello function as defined in the interface. Of course, dereferencing the interface works:

func callHello(i *myinter) {   
    (*i).hello()  // <- works!
}

But in structs, we can call the function directly, none of this cumbersome dereference notation is necessary:

func callHello(s *mystruct) {   
    s.hello()  // <- also works!
}

Why is this the case? Is there a reason why we must explicitly dereference interface pointers? Is Go trying to discourage me from passing interface pointers into functions?

Upvotes: 0

Views: 3497

Answers (3)

Volker
Volker

Reputation: 42413

Is Go trying to discourage me from passing interface pointers into functions?

Yes.

Pointer-to-interface is wrong in (almost*) all cases.

(* There are very rare and delicate cases where pointer-to-interface makes sense but chances are high you won't see them more than once every 5 years.)

(Nitpick: The language is called "Go". "golang.org" is the website. Basics like this are covered by the compatibility promise and do not depend on the version: Go 1.0, 1.12 and 1.16 behave exactly the same in this regard.)

Upvotes: 1

Stephen Dunne
Stephen Dunne

Reputation: 459

Simply remove the pointer and use the interface.

func callHello(i myinter) {   
    i.hello()  
}

This func will now accept either an instance of a struct that implements the interface, or a pointer to an instance of a struct that implements the interface.

func main() {
    instance := mystruct{}
    pointer := &mystruct{}
    callHello(instance)
    callHello(pointer)
}

outputs the following:

I am T!
I am T!
 
Program exited.

Upvotes: 0

Burak Serdar
Burak Serdar

Reputation: 51502

It is related to the way the type system works. An interface type I defines a method set. The method set is defined for type I, and not for type *I. Because of this, the use of *I is limited. It can be used when a function is to set the interface value, but it is rare:

func f(x *error) {
  *x = fmt.Errorf("Some error")
}

Note that the interface itself can have an underlying pointer value:

func f(x someInterface) {
   *x.(*someType) = value
}

func main() {
   x := someType{}
   f(&x)
}

This is different for non-interface types. When you define a method for a non-interface type T, the method is defined for both T and *T. If you define a method for *T, it is only defined for *T, and not for T.

Upvotes: 1

Related Questions