gpt4 book ai didi

methods - Go嵌入结构调用子方法而不是父方法

转载 作者:IT王子 更新时间:2023-10-29 00:40:31 25 4
gpt4 key购买 nike

这里是带有一个接口(interface)、一个父结构和 2 个子结构的 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 的调用,它调用 Circle 和 Rectangle 的 Shape.Area 方法,而不是调用 Circle.AreaRectangle.Area 方法。

这是 Go 中的错误吗?

感谢您的帮助。

最佳答案

实际上在您的示例中调用 ShapeInterface.PrintArea()Circle 的情况下工作得很好,因为您创建了一个 PrintArea() 方法对于类型 Circle。由于您没有为 Rectangle 类型创建 PrintArea(),因此将调用嵌入的 Shape 类型的方法。

这不是错误,这是预期的工作方式。围棋是not (quite) an object oriented language : 它没有类并且它 does not have type inheritance ;但它在 struct 级别和 interface 级别都支持称为 embedding 的类似构造,并且它确实有 methods .

你期望的是virtual methods : 你期望 PrintArea() 方法会调用“覆盖”的 Area() 方法,但是在 Go 中没有继承和虚方法。

Shape.PrintArea() 的定义是调用 Shape.Area(),这就是发生的事情。 Shape 不知道它是哪个结构,也不知道它是否嵌入其中,因此它无法将方法调用“分派(dispatch)”到虚拟的运行时方法。

Go Language Specification: Selectors描述评估 x.f 表达式(其中 f 可能是一个方法)以选择最终调用哪个方法时所遵循的确切规则。要点:

  • 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.

进入细节

圆形

Circle 的情况下:si.PrintArea() 将调用 Circle.PrintArea() 因为您创建了这样一个方法:

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

在这个方法中 c.Area() 被调用,其中 c 是一个 *Circle,所以带有 *Circle 的方法 将调用同样存在的接收器。

PrintArea(si) 调用 si.Area()。由于 si 是一个 Circle 并且有一个方法 Area()Circle 接收器,它被调用没问题.

矩形

如果是Rectangle si.PrintArea() 实际上会调用方法Shape.PrintArea() 因为你没有Rectangle 类型定义一个 PrintArea() 方法(没有接收方 *Rectangle 的方法)。而 Shape.PrintArea() 方法的实现调用 Shape.Area() 不是 Rectangle.Area() - 如前所述,Shape 不知道 Rectangle。所以你会看到

Rectangle1 : Area 0

打印而不是预期的 Rectangle1 : Area 20

但是,如果您调用 PrintArea(si)(传递 Rectangle),它会调用 si.Area(),这将是 Rectangle.Area() 因为存在这样的方法。

关于methods - Go嵌入结构调用子方法而不是父方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29390736/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com