Methods 转到嵌入式结构调用子方法而不是父方法
这里是一个Go代码示例,包含一个接口、一个父结构和两个子结构Methods 转到嵌入式结构调用子方法而不是父方法,methods,struct,go,parent-child,Methods,Struct,Go,Parent Child,这里是一个Go代码示例,包含一个接口、一个父结构和两个子结构 package main import ( "fmt" "math" ) // Shape Interface : defines methods type ShapeInterface interface { Area() float64 GetName() string PrintArea() } // Shape Struct : standard shape with an are
package main
import (
"fmt"
"math"
)
// Shape Interface : defines methods
type ShapeInterface interface {
Area() float64
GetName() string
PrintArea()
}
// Shape Struct : standard shape with an area equal to 0.0
type Shape struct {
name string
}
func (s *Shape) Area() float64 {
return 0.0
}
func (s *Shape) GetName() string {
return s.name
}
func (s *Shape) PrintArea() {
fmt.Printf("%s : Area %v\r\n", s.name, s.Area())
}
// Rectangle Struct : redefine area method
type Rectangle struct {
Shape
w, h float64
}
func (r *Rectangle) Area() float64 {
return r.w * r.h
}
// Circle Struct : redefine Area and PrintArea method
type Circle struct {
Shape
r float64
}
func (c *Circle) Area() float64 {
return c.r * c.r * math.Pi
}
func (c *Circle) PrintArea() {
fmt.Printf("%s : Area %v\r\n", c.GetName(), c.Area())
}
// Genreric PrintArea with Interface
func PrintArea (s ShapeInterface){
fmt.Printf("Interface => %s : Area %v\r\n", s.GetName(), s.Area())
}
//Main Instruction : 3 Shapes of each type
//Store them in a Slice of ShapeInterface
//Print for each the area with the call of the 2 methods
func main() {
s := Shape{name: "Shape1"}
c := Circle{Shape: Shape{name: "Circle1"}, r: 10}
r := Rectangle{Shape: Shape{name: "Rectangle1"}, w: 5, h: 4}
listshape := []c{&s, &c, &r}
for _, si := range listshape {
si.PrintArea() //!! Problem is Witch Area method is called !!
PrintArea(si)
}
}
我希望取得以下成果:
$ go run essai_interface_struct.go
Shape1 : Area 0
Interface => Shape1 : Area 0
Circle1 : Area 314.1592653589793
Interface => Circle1 : Area 314.1592653589793
Rectangle1 : Area 0
Interface => Rectangle1 : Area 20
我的问题是调用Shape.PrintArea
,它调用圆形和矩形的Shape.Area
方法,而不是调用Circle.Area
和Rectangle.Area
方法
这是围棋中的虫子吗
感谢您的帮助。实际上,在您的示例中,调用
ShapeInterface.PrintArea()
在圆
的情况下效果很好,因为您为类型圆
创建了PrintArea()
方法。由于您没有为矩形
类型创建PrintArea()
,因此将调用嵌入的形状
类型的方法
这不是错误,这是预期的工作。围棋是:它没有课和它;但是它在struct
级别和interface
级别上都支持一个类似的结构,称为嵌入,并且它确实有
您期望的是调用:您期望PrintArea()
方法将调用“overrided”Area()
方法,但在Go中没有继承和虚拟方法
Shape.PrintArea()
的定义是调用Shape.Area()
,这就是所发生的事情<代码>形状不知道它是哪个结构,也不知道它是否嵌入其中,因此它无法将方法调用“分派”到虚拟的运行时方法
描述了计算x.f
表达式(其中f
可能是一种方法)以选择最终调用哪种方法时所遵循的确切规则。要点:
- 选择器
可以表示类型f
的字段或方法T
,也可以表示嵌套类型f
的字段或方法T
。为达到f
而遍历的匿名字段数称为其在f
中的深度T
- 对于类型为
或T
的值*T
,其中x
不是指针或接口类型,T
表示x.f
中最浅深度的字段或方法,其中存在这样的T
f
Circle
:si.PrintArea()
将调用Circle.PrintArea()
,因为您创建了这样一个方法:
func (c *Circle) PrintArea() {
fmt.Printf("%s : Area %v\r\n", c.GetName(), c.Area())
}
在这个方法中,c.Area()
被调用,其中c
是一个*圆
,因此将调用同样存在的带有*圆
接收器的方法
PrintArea(si)
调用si.Area()
。由于si
是一个Circle
并且有一个方法Area()
和Circle
接收器,因此调用它没有问题
矩形
对于Rectangle
si.PrintArea()
将实际调用方法Shape.PrintArea()
,因为没有为Rectangle
类型定义PrintArea()
方法(没有带receiver的方法*Rectangle
)。而Shape.PrintArea()
方法的实现调用Shape.Area()
非Rectangle.Area()
——如前所述,Shape
不知道Rectangle
。你会明白的
Rectangle1 : Area 0
打印而不是预期的矩形1:区域20
但是如果你调用
PrintArea(si)
(传递矩形
),它会调用si.Area()
,这将是Rectangle.Area()
,因为这样的方法存在。更进一步,如果你想要/需要像func(s*Shape)PrintArea()
这样的东西,你只需要把它变成func-ShapeArea(s ShapeInterface)
;一种对任何类似形状的东西(任何提供适当方法的东西,例如Area()float64
)进行操作的函数。此外,在实际代码中,调用函数“PrintFoo”并将其输出到stdout不是一个好主意,而是使用io.Writer
或返回字符串以及所谓的“getter”通常在惯用的Go代码中不包含“Get”;即Name()字符串
而不是GetName()字符串
。