Go embedded struct call child method instead parent method

核能气质少年 提交于 2019-11-26 17:52:05

Actually in your example calling ShapeInterface.PrintArea() works just fine in case of a Circle because you created a PrintArea() method for the type Circle. Since you did not create a PrintArea() for the Rectangle type, the method of the embedded Shape type will be called.

This is not a bug, this is the intended working. Go is not (quite) an object oriented language: it does not have classes and it does not have type inheritance; but it supports a similar construct called embedding both on struct level and on interface level, and it does have methods.

What you expect is called virtual methods: you expect that the PrintArea() method will call the "overridden" Area() method, but in Go there is no inheritance and virtual methods.

The definition of Shape.PrintArea() is to call Shape.Area() and this is what happens. Shape does not know about which struct it is and if it is embedded in, so it can't "dispatch" the method call to a virtual, run-time method.

The Go Language Specification: Selectors describe the exact rules which are followed when evaluating an x.f expression (where f may be a method) to choose which method will be called in the end. Key Points:

  • A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested anonymous field of T. The number of anonymous fields traversed to reach f is called its depth in T.
  • For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f.

Going into details

Circle

In case of Circle: si.PrintArea() will call Circle.PrintArea() because you created such a method:

func (c *Circle) PrintArea() {
    fmt.Printf("%s : Area %v\r\n", c.GetName(), c.Area())
}

In this method c.Area() is called where c is a *Circle, so the method with *Circle receiver will be called which also exists.

PrintArea(si) calls si.Area(). Since si is a Cicle and there is a method Area() with Circle receiver, it is invoked no problem.

Rectangle

In case of Rectangle si.PrintArea() will actually call the method Shape.PrintArea() because you did not define a PrintArea() method for the Rectangle type (there is no method with receiver *Rectangle). And the implementation of Shape.PrintArea() method calls Shape.Area() not Rectangle.Area() - as discussed, Shape doesn't know about Rectangle. So you'll see

Rectangle1 : Area 0

printed instead of the expected Rectangle1 : Area 20.

But if you call PrintArea(si) (passing the Rectangle), it calls si.Area() which will be Rectangle.Area() because such method exists.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!