Go 指针接收器与值接收器混淆

Go 指针接收器与值接收器混淆,go,Go,我已经读了很多,但是指针接收器和值接收器之间的二分法仍然让我困惑 假设我们有这个 type Apple struct { color string } func (a *Apple) Eat() { fmt.Printf("Eating %s apple\n", a.color) } func main() { a := Apple{"red"} a.Eat() } 我认为这是一个错误,因为我们试图通过一个值(ais value)调用一个带有指针接收器的方

我已经读了很多,但是指针接收器和值接收器之间的二分法仍然让我困惑

假设我们有这个

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
is value)调用一个带有指针接收器的方法。但这是编译、运行和打印的

我的理解是,如果
a
是指针,那么它将适用于值接收器和指针接收器方法。但是当
a
是一个值时,它应该只适用于具有值接收器的方法,因为指针接收器方法不在方法集中

但上述情况似乎与此相矛盾。发生什么事。(我正在运行Go
1.8.3

--更新-- 事实证明有两件事需要注意

第一个是实际规则,第二个是我们在使用这些接收器时得到的编译器帮助

规则是指针接收器方法不能通过值调用——它必须是指针。但是当我们调用
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编译器为我们提供的“忘记”该规则的帮助非常重要——特别是在方法调用表达式中


在调用
a.Eat()
后,尝试在
Eat()方法中修改
a.color
,并在
main()中打印
a.color

然后将
Eat()
方法的参数更改为非指针。您将看到它在这两种情况下都能正常工作

要真正回答您的问题:go编译器会自动确定您是需要值还是指针。如果您有一个指针并调用一个值接收器方法,那么这也是另一种方式

func (a *Apple) Eat() {
    a.color = "green"
    fmt.Printf("Eating %s apple", a.color)
}

func main() {
    a := Apple{"red"}
    a.Eat()
    fmt.Printf("Eating %s apple", a.color)
}