douzhenzu0247 2017-06-27 12:28
浏览 46

指针接收器与值接收器的混淆[重复]

Been reading about it a lot, but the dichotomy between Pointer receiver and Value receiver still confuses me.

Let's say we have this...

type Apple struct {
    color string
}

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

func main() {
    a := Apple{"red"}

    a.Eat()
}

I would think that this is an error as we are trying to call a method with Pointer receiver via a value (a is value). But this compiles and runs and prints.

My understanding is that if a was a pointer, then it would work for both value receiver and pointer receiver methods. But when a is a value, then it should only work with methods that have value receivers, as pointer receiver methods are NOT in the method set.

But the above seems to contradict this. What's going on. (I am running Go 1.8.3).

https://play.golang.org/p/eWkDHwIgOZ

-- Update --

Turns out there are two things to be aware of.

First is the actual rule, and second is the compiler aid we get in using these receivers.

The rule is that a pointer receiver method can NOT be called via value -- it has to be a pointer. But when we call a.Eat (a being a value) -- the compiler does its helping hand and turns a into &a. The rule is still enforced - albeit "behind the scene".

The rule asserts itself in interfaces though.

Let's say we have an interface...

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
}

Here, within the call to EatMore(a), the compiler does not turn a into &a -- and hence we get the error. The correct way would be, as expected, EatMore(&a).

Hence, it is important to distinguish between the rule from the help Go compiler offers us in "forgetting" about this rule -- especially in method call expressions.

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

</div>
  • 写回答

1条回答 默认 最新

  • douxia6554 2017-06-27 12:43
    关注

    Try modifying a.color in your Eat() method and print a.color in main() after calling a.Eat().

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

    Then change the parameter of the Eat() method to a non-pointer. You will see it works as expected in both cases.

    To actually answer your question: The go compiler automatically determines whether you need the value or the pointer. This also works the other way around, if you have a pointer and call a value receiver method.

    评论

报告相同问题?

悬赏问题

  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题