【发布时间】:2017-11-30 12:14:15
【问题描述】:
读了很多,但是指针接收器和值接收器之间的二分法仍然让我感到困惑。
假设我们有这个......
type Apple struct {
color string
}
func (a *Apple) Eat() {
fmt.Printf("Eating %s apple\n", a.color)
}
func main() {
a := Apple{"red"}
a.Eat()
}
我认为这是一个错误,因为我们试图通过一个值(a 是值)调用带有指针接收器的方法。但这会编译、运行和打印。
我的理解是,如果a 是一个指针,那么它适用于值接收器和指针接收器方法。但是当a 是一个值时,它应该只适用于具有值接收器的方法,因为指针接收器方法不在方法集中。
但以上似乎与此相矛盾。这是怎么回事。 (我正在运行 Go 1.8.3)。
https://play.golang.org/p/eWkDHwIgOZ
-- 更新--
原来有两件事需要注意。
首先是实际规则,其次是我们在使用这些接收器时获得的编译器帮助。
规则是指针接收器方法不能通过值调用——它必须是指针。但是当我们调用a.Eat(a 是一个值)时,编译器会伸出援手,将a 转换为&a。该规则仍在执行 - 尽管是“幕后”。
该规则在接口中声明自己。
假设我们有一个接口......
type Edible interface {
Eat()
}
// Note that this is not a method, it is a simple function.
func EatMore(x Edible) {
fmt.Println("Eating more...")
x.Eat()
}
func main() {
a := Apple{"red"}
a.Eat() // Okay -- because compiler is helping
EatMore(a) // Wrong -- the rule asserts, compiler does not help
}
在这里,在对EatMore(a) 的调用中,编译器不会将a 转换为&a——因此我们得到了错误。正如预期的那样,正确的方法是EatMore(&a)。
因此,区分规则和 Go 编译器为我们提供的“忘记”该规则的帮助非常重要——尤其是在方法调用表达式中。
【问题讨论】:
标签: go