ter*_*975 4 methods struct parent-child go
这里是Go代码示例,包含Interface,Parent Struct和2 Children Structs
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)
}
}
Run Code Online (Sandbox Code Playgroud)
我有结果:
$ 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
Run Code Online (Sandbox Code Playgroud)
我的问题是调用Shape.PrintArea
该调用Shape.Area
方法Circle和Rectangle,而不是调用Circle.Area
和Rectangle.Area
方法.
这是Go中的一个错误吗?
谢谢你的帮助.
实际上在你的例子中,ShapeInterface.PrintArea()
在a的情况下调用工作正常,Circle
因为你PrintArea()
为类型创建了一个方法Circle
.由于您没有PrintArea()
为Rectangle
类型创建,因此Shape
将调用嵌入类型的方法.
这不是错误,这是预期的工作.Go 不是(完全)一种面向对象的语言:它没有类,也没有类型继承 ; 但是它支持一个类似的构造,在层次和层次上都称为嵌入,它确实有方法.struct
interface
您期望的是虚拟方法:您希望该PrintArea()
方法将调用"重写" Area()
方法,但在Go中没有继承和虚方法.
定义Shape.PrintArea()
是调用Shape.Area()
,这就是发生的事情.Shape
不知道它是哪个结构以及它是否嵌入,因此它不能将方法调用"调度"到虚拟的运行时方法.
的围棋语言规范:选择器描述的评价时,其遵循确切规则x.f
表达(其中,f
可以是方法)选择哪种方法,将在结束时调用.关键点:
- 选择器
f
可以表示一个字段或方法f
的类型的T
,或者它可以指字段或方法f
嵌套的匿名字段的T
.走过达到匿名的字段数f
被称为其深度在T
.- 对于值
x
类型的T
或*T
其中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())
}
Run Code Online (Sandbox Code Playgroud)
在这个方法c.Area()
中调用where c
是a *Circle
,所以*Circle
调用带接收器的方法也存在.
PrintArea(si)
电话si.Area()
.由于si
是一个Cicle
,有一个方法Area()
与Circle
接收机,它被调用没有问题.
如果Rectangle
si.PrintArea()
将实际调用该方法,Shape.PrintArea()
因为您没有PrintArea()
为该Rectangle
类型定义方法(没有接收器的方法*Rectangle
).和执行Shape.PrintArea()
方法调用Shape.Area()
没有 Rectangle.Area()
-作为讨论,Shape
不知道Rectangle
.所以你会看到
Rectangle1 : Area 0
Run Code Online (Sandbox Code Playgroud)
打印而不是预期的Rectangle1 : Area 20
.
但是如果你调用PrintArea(si)
(传递Rectangle
),它会调用si.Area()
哪个Rectangle.Area()
因为这样的方法存在.