英文:
GoLang embedded struct class hierarchy
问题
我正在为您翻译以下内容:
我正在阅读这篇博文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()**可以正常工作,但通过接口调用时却不起作用。
英文:
I was reading this blogpost http://www.hydrogen18.com/blog/golang-embedding.html and came across these lines
>
There is an important distinction to observe here. If myParent is an instance of Parent the value myParent cannot act as a Valueable. You must use the the value &myParent, a pointer to the instance, to act as a Valueable. This is because the method Value receives a *Parent not a Parent.
I have created a sample https://play.golang.org/p/ojTKZfx97g . So the questions is why calling the method myparent.Value() works by itself but does not work when called through interface
答案1
得分: 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
的方法集由所有声明了接收器类型为*T
或T
的方法组成(也就是说,它还包含了T
的方法集)。
所以Parent
类型并没有实现Valueable
接口,但*Parent
类型实现了它。
因此,你可以将*Parent
(Parent
的指针)作为Valuable
值传递给你的方法,因为它实现了该接口。你可以使用取地址操作符&
轻松地获得一个指针:
fmt.Println(callValueable(&myparent)) // 这样可以工作
英文:
Your callValueable(v Valueable)
function has a parameter of type Valueable
which is an interface:
type Valueable interface {
Value() int64
}
You can pass any value to it which implements this interface. Your Parent
type does not, because even though it has a Value()
method, that method has a pointer receiver:
func (i *Parent) Value() int64{
return i.value
}
And according to the Go Language Specification (Method sets and Interface types) the method set of Parent
does not include this method, only the method set of *Parent
. Quoting from the Spec:
> ...The method set of any other type T
consists of all methods declared with receiver type T
. The method set of the corresponding pointer type *T
is the set of all methods declared with receiver *T
or T
(that is, it also contains the method set of T
).
So the type Parent
does not implement the Valueable
interface but the type *Parent
does implement it.
So you can pass a *Parent
(a pointer to Parent
) as a Valuable
value to your method, because that implements the interface. You can easily obtain a pointer by using the address &
operator:
fmt.Println(callValueable(&myparent)) // This WORKS
答案2
得分: 1
根据《Effective Go》的说法,如果值是可寻址的,那么在调用指针接收器方法时,Go 会自动插入 & 符号。
我进一步研究了这个问题,发现我对于“可寻址”的理解是错误的。我一直以为像 C++ 一样,只要是左值就是可寻址的。但是在 Go 语言中,并不是所有的东西都是可寻址的,比如:
- 存储在接口中的具体值是不可寻址的。
- map 元素是不可寻址的。
那么有趣的问题是,为什么接口的具体类型不可寻址,这样 Go 就可以自动插入 & 符号了呢?我在这里找到了一个链接:https://groups.google.com/forum/#!topic/golang-nuts/-ZoCu5m0kJ4。我引用了 Steven Blenkinsop 的答案,你可以在最后找到。
从某种程度上说,这是因为语言规范是这样规定的。但归根结底,是因为无法获取一个指针作为接收器传递的限制。你不能获取接口内部值的地址,因为它的类型可能会改变(你可以将不同类型的值赋给接口),还有其他原因。所以,如果你需要一个指针接收器,指针本身就需要在接口中。
所以我认为,对于接口或者 map 来说,由于底层内存地址可能会被其他线程改变,所以 Go 不会自动为我们插入 & 符号,因为它无法保证内存地址在整个函数调用生命周期内都是有效的。
英文:
As per Effective Go if the value is addressable then go will automatically insert & when calling pointer receiver method.
I did further research on this and looks like my understanding what is addressable is wrong. I was thinking along the line of c++ whereas as long it is lvalue then it is addressable. But it seem that in golang not everything is addressable such as
- concrete value stored in an interface is not addressable
- map element is not addressable
The interesting question then is why concrete type of interface is not addressable so that golang can automatically do &. I found this https://groups.google.com/forum/#!topic/golang-nuts/-ZoCu5m0kJ4. I am quoting the answer by Steven Blenkinsop which you can find at the end
> On one level, it's because the language spec says so. But ultimately, yes, it's because of a limitation on getting a pointer to pass as the receiver. You can't take the address of the value inside an interface, since its type could change (you could assign a differently typed value to the interface), among other reasons. So, if you need a pointer receiver, the pointer itself needs to be in the interface.
So the way I see for interface or map since the underlying memory address might change maybe by another thread that is why go does not automatically insert & for us as it cannot guarantee the memory address will be valid throughout the function call life cycle.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论