GoLang嵌入式结构体的类层次结构

3
我正在阅读这篇博客文章http://www.hydrogen18.com/blog/golang-embedding.html,看到了以下内容:

这里有一点要注意。如果myParent是Parent类的实例,则myParent的值无法充当Valueable。您必须使用值 &myParent,即实例的指针,作为Valueable。这是因为方法Value接收一个*Parent而不是Parent。

我创建了一个示例https://play.golang.org/p/ojTKZfx97g。所以问题是,为什么单独调用方法myparent.Value()可以运行,但通过接口调用时不起作用?
2个回答

1
根据《Effective Go》的说法,如果值是可寻址的,则在调用指针接收器方法时,Go会自动插入 & 符号。
我进一步研究了这个问题,发现我的理解“可寻址”是错误的。我之前认为只要是lvalue就是可寻址的,但在golang中并非所有东西都是可寻址的,例如:
- 存储在接口中的具体值不可寻址 - map元素不可寻址
有趣的问题是,为什么接口的具体类型不可寻址,这样golang就可以自动使用&符号了。我找到了https://groups.google.com/forum/#!topic/golang-nuts/-ZoCu5m0kJ4上Steven Blenkinsop的回答,你可以在结尾处找到。
在某种程度上,这是因为语言规范如此规定。但最终,确实是由于获取指针作为接收器的限制。你不能取出接口内部值的地址,因为它的类型可能会改变(你可以将不同类型的值分配给接口),还有其他原因。因此,如果需要一个指针接收器,指针本身需要在接口中。
所以我认为对于接口或映射,由于底层内存地址可能会被另一个线程更改,因此Go不会自动为我们插入&符号,因为它无法保证内存地址在函数调用生命周期内始终有效。

1

您的 callValueable(v Valueable) 函数有一个类型为 Valueable 的参数,它是一个接口:

type Valueable interface {
    Value() int64
}

你可以将任何实现此接口的值传递给它。你的`Parent`类型不行,因为即使它有一个`Value()`方法,该方法也具有指针接收器:
func (i *Parent) Value() int64{
    return i.value
}

根据Go语言规范(方法集接口类型),Parent的方法集不包括此方法,只有*Parent的方法集。引用规范中的一段话:

……任何其他类型T的方法集由所有声明为接收器类型T的方法组成。相应指针类型*T的方法集是所有声明为接收器类型*TT的方法的集合(也就是它还包含了T的方法集)。

因此,类型Parent没有实现Valueable接口,但类型*Parent实现了该接口。
所以您可以将*Parent(即Parent指针)作为Valuable值传递给您的方法,因为它实现了该接口。您可以使用地址运算符&轻松获得指针:
fmt.Println(callValueable(&myparent)) // This WORKS

谢谢icza。我认为对于我来说问题的关键是为什么golang在使用接口时不会自动插入&,而在调用__myparent.value()__时会插入&。由于评论空间有限,我将在另一个答案中添加更多信息。 - tabiul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接