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

huangapple go评论82阅读模式
英文:

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的方法集由所有声明了接收器类型为*TT的方法组成(也就是说,它还包含了T的方法集)。

所以Parent类型并没有实现Valueable接口,但*Parent类型实现了它。

因此,你可以将*ParentParent指针)作为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.

huangapple
  • 本文由 发表于 2015年2月21日 00:56:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/28634221.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定