Given the following Go code example:
package main
import "fmt"
type greeter interface {
hello()
goodbye()
}
type tourGuide struct {
name string
}
func (t tourGuide) hello() {
fmt.Println("Hello", t.name)
}
func (t *tourGuide) goodbye() {
fmt.Println("Goodbye", t.name)
}
func main() {
var t1 tourGuide = tourGuide{"James"}
t1.hello() // Hello James
t1.goodbye() // Goodbye James (same as (&t1).goodbye())
var t2 *tourGuide = &tourGuide{"Smith"}
t2.hello() // Hello Smith
t2.goodbye() // Goodbye Smith (same as (*t2).hello())
// illegal: t1 is not assignable to g1 (why?)
// var g1 greeter = t1
var g2 greeter = t2
g2.hello() // Hello Smith
g2.goodbye() // Goodbye Smith
}
I'm able to call the two methods of the struct tourGuide
using either a variable of type tourGuide t1
or a pointer to tourGuide t2
. In other words, I can call a method with T
receiver using a variable of type T
or *T
. Similarly, I can call a method with *T
receiver using a variable of type T
(if T
is addressable) or *T
. I understand that the compiler handles the differences here (see my comments in the code).
However, things change when we are implementing interfaces. In the above code, a variable of type greeter
interface is assignable from a pointer to tourGuide
but not from a tourGuide
.
Can anyone tell me why this is the case? Why am I able to call t1.hello()
and t1.goodbye()
but somehow t1
is not enough for the interface greeter
?
If a method has a pointer receiver, only a pointer value can be used as the receiver value. So to call this method on some value, the value itself must be a pointer, or it must be possible to acquire its address (to be used as the receiver).
If you have a variable for example, it is addressable and thus it's possible to get its address and use that as the receiver. And the spec allows you to do this, this happens automatically.
Values wrapped in interfaces are not addressable. When an interface value is created, the value that is wrapped in the interface is copied. It is therefore not possible to take its address. Theoretically you could allow to take the address of the copy, but that would be the source of (even) more confusion than what benefit it would provide, as the address would point to a copy, and methods with pointer receiver could only modify the copy and not the original.
See this answer which details / proves that values are copied when the interface value is created: How can a slice contain itself?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With