Наследование в структуре данных go - PullRequest
0 голосов
/ 10 июля 2019

Есть ли лучший способ получить наследство в го? (В c # мы используем абстрактный класс и интерфейсы для достижения аналогичного поведения). Пожалуйста, ознакомьтесь с кодом ниже, чтобы понять проблему.

Я пытался использовать интерфейс в Go, но я не могу получить доступ к полям данных структуры.

type Vehicle struct {
    Id          int
    Name        string
    VehicleType VehicleTypeBase
}

type VehicleTypeBase struct {
    Id     int
    Name   string
    Milage int
}

type VehicleTypeSedan struct {
    VehicleTypeBase
    IsABSEnabled bool
}

type VehicleTypeHatchback struct {
    VehicleTypeBase
    Is4WheelDriveEnabled bool
}

func main() {
    var veh Vehicle

    veh = Vehicle{
        Id:   1,
        Name: "Zeep Compass",
        VehicleType: VehicleTypeSedan{
            Id:           1,
            Name:         "Sedan",
            Milage:       13,
            IsABSEnabled: true,
        },
    }
}

// Above initialization gives error. Here, I would like to understand that how // to achieve inheritance using base class
// in Golang. Is there a way to solve this situation in Go??

Сообщение об ошибке:

. \ Main.go: 40: 3: нельзя использовать литерал VehicleTypeSedan (тип VehicleTypeSedan) в качестве типа VehicleTypeBase в значении поля

Ответы [ 2 ]

0 голосов
/ 10 июля 2019

Структурное встраивание - вот как предпочитает go lang Идея композиции лучше наследования.

https://golang.org/doc/effective_go.html#embedding

Вы должны объявить интерфейс для Транспортного средства, и все Транспортные средства реализуют этот интерфейс.

Это проблема уровня проектирования, а не просто исправление ошибки. Поскольку не совсем понятно, как именно вы собираетесь использовать и бороться с транспортными средствами. Я сделаю некоторые предположения.

Путем встраивания следует встраивать повторно используемую структуру в определенные структуры.

type VehicleTypeGeneral struct {
    Id     int
    Name   string
    Milage int
}

//Embed VehicleTypeGeneral
type VehicleTypeHatchback struct {
    VehicleTypeGeneral
    Is4WheelDriveEnabled bool
}

Если мы создаем экземпляр vh из VehicleTypeHatchback, тогда мы можем получить доступ к полям VehicleTypeHatchback, а также к встроенной структуре VehicleTypeGeneral, такой как vh.Is4WheelDriveEnabled и vh.VehicleTypeGeneral.Name

Если VehicleTypeGeneral реализует интерфейс, такой как Vehicle interface, то VehicleTypeHatchback также реализует это. Вы можете переопределить, реализовав методы.

Я добавил пример проверки типа в функции processSpecificVehicle. Однако эти вещи замедляют выполнение. Вместо этого попробуйте использовать подходы, упомянутые в processVehicle и processAbsVehicle

Также интерфейсы не должны иметь много методов. Одного или двух достаточно, в противном случае это нарушение принципа разделения интерфейса. Сохраняйте интерфейсы короткими и осмысленными и проектируйте их с точки зрения потребителя интерфейсов.

Полный пример с некоторыми допущениями:

package main
import "fmt"

type Vehicle interface {
    GetId() int
    GetName() string
}

type AbsVehicle interface {
    IsAbsEnabled() bool   
}

type VehicleTypeGeneral struct {
    Id     int
    Name   string
    Milage int
}

func (v *VehicleTypeGeneral) GetId() int{
    return v.Id
}

func (v *VehicleTypeGeneral) GetName() string{
    return v.Name
}

type VehicleTypeSedan struct {
    VehicleTypeGeneral
    IsABSEnabled bool
}

func(vs *VehicleTypeSedan) IsAbsEnabled() bool {
    return vs.IsABSEnabled
}

type VehicleTypeHatchback struct {
    VehicleTypeGeneral
    Is4WheelDriveEnabled bool
}

func main() {
    println("Hello")

    var vehicle = VehicleTypeSedan{IsABSEnabled: true, VehicleTypeGeneral: VehicleTypeGeneral{Id:1001,Name:"Sedan 1", Milage:12}}

    processVehicle(&vehicle)
    processAbsVehicle(&vehicle)
    processSpecificVehicle(&vehicle)
    processSedan(&vehicle)
}

func processVehicle(vehicle Vehicle){
    println(vehicle.GetId())
    println(vehicle.GetName())  
}


func processAbsVehicle(vehicle AbsVehicle){
    println(vehicle.IsAbsEnabled())

}

func processSpecificVehicle(vehicle Vehicle){
    switch v := vehicle.(type) {
    case *VehicleTypeSedan:
        fmt.Printf("Its a sedan %v with ABS %v ", v.GetName(), v.IsAbsEnabled())
    case *VehicleTypeHatchback:
        fmt.Printf("Its a VehicleTypeHatchback %v", v.GetName())
    default:
        fmt.Printf("Its a Vehicle")
    }

}

func processSedan(vs *VehicleTypeSedan){
    println("\nprocess sedan")
    println(vs.VehicleTypeGeneral.Name)
    println(vs.IsABSEnabled)
}
0 голосов
/ 10 июля 2019

Это может работать!

type Vehicle struct {                        
    Id          int
    Name        string
    VehicleType VehicleTypeInterface
}

type VehicleTypeInterface interface{}

type VehicleTypeBase struct {
    Id     int
    Name   string
    Milage int
}

type VehicleTypeSedan struct {
    VehicleTypeBase
    IsABSEnabled bool
}

type VehicleTypeHatchback struct {
    VehicleTypeBase
    Is4WheelDriveEnabled bool
}

func main() {
    var veh Vehicle

    veh = Vehicle{
        Id:   1,
        Name: "Zeep Compass",
        VehicleType: VehicleTypeSedan{
            VehicleTypeBase: VehicleTypeBase{
                Id:     3,
                Name:   "Sedan",
                Milage: 13,
            },
            IsABSEnabled: true,
        },
    }
    fmt.Printf("%+v", veh)
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...