简体   繁体   中英

GoLang embedded struct class hierarchy

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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM