Reputation: 4572
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
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
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
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