我正在尝试学习 Go,但我一直在努力反对它的一些概念,这些概念与其他语言相比有不同的应用。
假设我有一个结构
type Vehicle struct {
Seats int
}
Run Code Online (Sandbox Code Playgroud)
我现在想要另一个结构,其中嵌入Vehicle:
type Car struct {
Vehicle
Color string
}
Run Code Online (Sandbox Code Playgroud)
据我了解,该Car结构现在嵌入了 Vehicle.
现在我想要一个可以容纳任何车辆的功能
func getSeats(v Vehicle){
return v.Seats
}
Run Code Online (Sandbox Code Playgroud)
但每当我尝试通过Car:
getSeats(myCar)
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
cannot use myCar (value of type Car) as Vehicle value in argument to getSeats
但我的 IDE 告诉我myCar有一个Seats属性!
由此我了解到嵌入与继承不同。
我的问题是;是否有类似于 c++ 的结构继承,其中函数可以采用基本结构,或者这是 Go 处理完全不同的东西?我如何在“Go way”中实现这样的事情?
就像你提到的,Go 没有典型意义上的继承。嵌入实际上只是语法糖。
嵌入时,您可以向结构体添加一个与要嵌入的类型名称完全相同的字段。嵌入结构的任何方法都可以在嵌入它们的结构上调用,这只不过是转发它们。
一个问题是,如果嵌入另一个结构的结构已经声明了一个方法,那么它将优先于转发它,如果您想这样考虑的话,这允许您对函数进行排序。
正如您所注意到的,我们不能用作Car即使Vehicle嵌入Car,Vehicle因为它们严格来说不是同一类型。但是任何嵌入的结构Vehicle都将具有由 定义的所有方法Vehicle,因此,如果我们定义一个Vehicle实现的接口,则所有嵌入的类型Vehicle也应该实现该接口。
例如:
package main
import (
"fmt"
)
type Seater interface {
Seats() int
}
type Vehicle struct {
seats int
}
func (v *Vehicle) Seats() int {
return v.seats
}
type Car struct {
Vehicle
Color string
}
type Bike struct {
Vehicle
Flag bool
}
// A bike always has 1 seat
func (b *Bike) Seats() int {
return 1
}
type Motorcycle struct {
Vehicle
Sidecar bool
}
// A motorcycle has the base amounts of seats, +1 if it has a side car
func (m *Motorcycle) Seats() int {
return m.Vehicle.seats + 1
}
func getSeats(v Seater) int {
return v.Seats()
}
func main() {
fmt.Println(getSeats(&Bike{
Vehicle: Vehicle{
seats: 2, // Set to 2 in the Vehicle
},
Flag: true,
}))
fmt.Println(getSeats(&Motorcycle{
Vehicle: Vehicle{
seats: 1,
},
Sidecar: true,
}))
fmt.Println(getSeats(&Car{
Vehicle: Vehicle{
seats: 4,
},
Color: "blue",
}))
}
Run Code Online (Sandbox Code Playgroud)
这打印:
1
2
4
Run Code Online (Sandbox Code Playgroud)
在调用Bike该方法的情况下,这就是为什么即使其值为 ,它也会返回。Bike.Seats1seatsVehicle2
Motorcycle在该方法也被调用的情况下Motorcycle.Seats,但在这里我们可以访问嵌入类型并仍然使用它来获取结果。
在 的情况下Car,Vehicle.Seats将调用该方法,因为Car不会“覆盖” Seats。