Methods 转到嵌入式结构调用子方法而不是父方法

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

这里是一个Go代码示例,包含一个接口、一个父结构和两个子结构

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()字符串