IsaIkari
IsaIkari

Reputation: 1154

How to check if an attribute exists in an object's dynamic struct

I'm confused about how to check if an attribute exists in an object's dynamic struct. I.e. if we have the following structs:

type Animal struct {
    Name string
    Origin string
}

type Bird struct {
    Animal
    Speed float32
    CanFly bool
}

type Bear struct {
    Animal
    Lazy bool
}

And now I have a function using Animal as a parameter:

func checkAminalSpeed (a Animal){

    // if the struct of current animal doesn't have the Speed attribute
    // print ("I don't have a speed")
    
    //otherwise, return the speed of this animal
}

This function is trying to check the varible's runtime type to choose action.

I'd like to know in this case, how to write this checkAminalSpeed function? Thanks!

Upvotes: 0

Views: 2186

Answers (2)

Para
Para

Reputation: 1387

mkopriva is right. Go does not support inheritance, you can use reflect and interface{} also

ps: reflect cost more time than interface

package main
import (
    "fmt"
    "reflect"
)

type Animal struct {
    Name string
    Origin string
}

type Bird struct {
    Animal
    Speed float32
    CanFly bool
}

type Bear struct {
    Animal
    Lazy bool
}

func checkAminalSpeed (a interface{}){
    v := reflect.ValueOf(a)
    if f, ok := v.Type().FieldByName("Speed"); ok{
        fmt.Printf("%v\n", f)
    }

}

func main() {
    checkAminalSpeed(Bird{})
    checkAminalSpeed(Bear{})
}

Upvotes: 1

mkopriva
mkopriva

Reputation: 38303

Go does not support inheritance, but perhaps you'll find the following approach tolerable.

Use an interface to define the Animal's behaviour:

type Animal interface {
    GetName() string
    GetOrigin() string
    GetSpeed() float32
}

Use a "base" type that will contain common fields and also implement the behaviour:

type AnimalBase struct {
    Name   string
    Origin string
}

func (a AnimalBase) GetName() string   { return a.Name }
func (a AnimalBase) GetOrigin() string { return a.Origin }
func (a AnimalBase) GetSpeed() float32 { return -1 }

Embed the "base" type and override any behaviour you need to:

type Bird struct {
    AnimalBase
    Speed  float32
    CanFly bool
}

func (b Bird) GetSpeed() float32 { return b.Speed }

And then...

func checkAminalSpeed(a Animal) {
    if speed := a.GetSpeed(); speed == -1 {
        fmt.Println("I don't have speed")
    } else {
        fmt.Println(speed)
    }
}

https://play.golang.org/p/KIjfC7Rdyls

Upvotes: 2

Related Questions