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 }
In the above code, you can call the two methods of the struct tourGuide using either a variable of type tourGuide (t1) or a pointer to tourGuide (t2). However, when implementing interfaces, things change. A variable of type greeter interface is assignable from a pointer to tourGuide, but not from a tourGuide value. Why is this the case?
To understand the reason, it's important to understand the concept of receiver types and value semantics. Methods in Go can have either a value receiver or a pointer receiver. A value receiver method is invoked on a copy of the value, while a pointer receiver method is invoked on the original value.
When a value is copied, it creates a new independent copy of the original value. Any modifications made to the copy do not affect the original value. This is known as value semantics.
In the tourGuide example, the hello method has a value receiver, and the goodbye method has a pointer receiver. When you call t1.hello(), a copy of t1 is created, and the hello method is invoked on the copy. When you call t1.goodbye(), the goodbye method is invoked on the original t1 value.
Interfaces in Go are implemented by value semantics. This means that when a value is assigned to an interface, a copy of the value is created. In the case of a pointer receiver method, this means that the copy of the value does not have an address, and therefore the method cannot be invoked on it.
For example, when you assign t1 to g1 (which is an interface value) in the following line of code:
// illegal: t1 is not assignable to g1 (why?) // var g1 greeter = t1
a copy of t1 is created, and the hello and goodbye methods are implemented on the copy. However, as the copy does not have an address, the goodbye method cannot be invoked on it.
In contrast, when you assign t2 to g2 in the following line of code:
var g2 greeter = t2
a copy of t2 (which is a pointer to tourGuide) is created, and the hello and goodbye methods are implemented on the copy of the pointer. In this case, the copy of the pointer has an address, so the goodbye method can be invoked on it.
In summary, the reason why a variable of type greeter interface is assignable from a pointer to tourGuide but not from a tourGuide value is because interfaces are implemented by value semantics. When a value is assigned to an interface, a copy of the value is created, and if the methods of the interface have pointer receivers, they cannot be invoked on the copy because the copy does not have an address.
The above is the detailed content of Why can\'t a Go `greeter` interface be assigned a `tourGuide` value, but can be assigned a pointer to a `tourGuide`?. For more information, please follow other related articles on the PHP Chinese website!