go数据结构中的继承

Is there a better way to achieve the inheritance in go? (In c# we use Abstract class and Interfaces to achieve similar behavior). Please refer below code to understand the problem.

I tried using interface in Go but I am unable to access the data fields of struct.

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??

The error message is:

.\main.go:40:3: cannot use VehicleTypeSedan literal (type VehicleTypeSedan) as type VehicleTypeBase in field value

It's can work!

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)
}

Struct embedding is how go lang prefers. Composition is better than inheritance is the idea.

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

You should declare an interface for Vehicle and all the Vehicles implement that interface.

This is design level problem than just fixing the error. Since its not clear exactly how you are going to use and deal with Vehicles. I will make some assumptions.

By Embedding way should embed a reusable struct inside specific structs.

type VehicleTypeGeneral struct {
    Id     int
    Name   string
    Milage int
}

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

If we creates instance vh of VehicleTypeHatchback then we can access fields of VehicleTypeHatchback as well as embedded struct VehicleTypeGeneral like vh.Is4WheelDriveEnabled and vh.VehicleTypeGeneral.Name

If VehicleTypeGeneral implement interface like Vehicle interface then VehicleTypeHatchback also implements that. You can override by implementing the methods though.

I have added type check example in processSpecificVehicle function. However these things slow the execution. Instead try to use the approached mentioned in processVehicle and processAbsVehicle

Also the interfaces should not have to many methods. One or two are enough other wise it is violation of interface segregation principle. Keep the interfaces short and meaningful and design them from the prospective of consumer of interfaces.

Complete example with certain assumptions:

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("
process sedan")
    println(vs.VehicleTypeGeneral.Name)
    println(vs.IsABSEnabled)
}