Go 中的嵌入与继承

Den*_*s M 4 go

我正在尝试学习 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”中实现这样的事情?

Dyl*_*ink 5

就像你提到的,Go 没有典型意义上的继承。嵌入实际上只是语法糖。

嵌入时,您可以向结构体添加一个与要嵌入的类型名称完全相同的字段。嵌入结构的任何方法都可以在嵌入它们的结构上调用,这只不过是转发它们。

一个问题是,如果嵌入另一个结构的结构已经声明了一个方法,那么它将优先于转发它,如果您想这样考虑的话,这允许您对函数进行排序。

正如您所注意到的,我们不能用作Car即使Vehicle嵌入CarVehicle因为它们严格来说不是同一类型。但是任何嵌入的结构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,但在这里我们可以访问嵌入类型并仍然使用它来获取结果。

在 的情况下CarVehicle.Seats将调用该方法,因为Car不会“覆盖” Seats