【问题标题】:Pointer receiver vs value receiver confusion [duplicate]指针接收器与值接收器混淆[重复]
【发布时间】: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.Eata 是一个值)时,编译器会伸出援手,将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 编译器为我们提供的“忘记”该规则的帮助非常重要——尤其是在方法调用表达式中。

https://play.golang.org/p/p3-LUlbmCg

【问题讨论】:

    标签: go


    【解决方案1】:

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

    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)
    }
    

    然后将Eat()方法的参数改为非指针。您将看到它在两种情况下都按预期工作。

    实际回答您的问题:go 编译器会自动确定您需要值还是指针。如果你有一个指针并调用一个值接收器方法,这也可以反过来工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-04
      • 2015-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多