Charlie Parker
Charlie Parker

Reputation: 5201

What is the "go" way to checking custom types in go?

I was trying to test the exact type of an object (either a costume struct or interface) in golang and was trying to figure out how to do it a way that does not real like a cheap hack. (Notice that built in types like strings, ints, floats, slices, etc are not what I am asking about).

Say that I have a Animal interface that implements a Speak method:

type Animal interface {
    Speak() string
}

and a Dog struct that implements that interface:

type Dog struct {
}

func (d Dog) Speak() string {
    return "Woof!"
}

say I have some variable x, how do I check what struct type it has and act accordingly?

For example I wanted something like:

func isDog(thing Animal{}) bool {
    if reflect.TypeOf(thing) == packageName.Dog{
        return true
    }else{
        return false
    }
}

The only solution that I thought of doing was not really what I wanted to do but I guess it works. First create an empty struct of the type I want to check and then use the reflect package to check for equality. Something like:

func isDog(thing Interface{}) bool {
    d := Dog{}
    if reflect.TypeOf(thing) == reflect.TypeOf(d){
        return true
    }else{
        return false
    }
}

The reason I didn't really like that is, say I have a larger code that I need a switch statement eventually. Then, I have to write so much extra code that I feel is unnecessary, like, I need to create the number of many empty struct types as I have cases. It seems unnecessary and really ugly. Is that the only way to do it? I also wanted it to be flexible enough to me it check for pointers too. Something like:

func isDog(thing Interface{}) bool {
    d := Dog{}
    if reflect.TypeOf(thing) == packageName.Dog{
        return true
    }else if reflect.TypeOf(thing) == *packageName.Dog{
        return true
    }else{
        return false
    }
}

Upvotes: 1

Views: 580

Answers (2)

Janotte Aphex
Janotte Aphex

Reputation: 21

The idiomatic way is to use a type switch rather than type assertions directly.

func isDog(animal Animal) bool {
    switch animal.(type) {
    case Dog:
    case *Dog:
    default:
        return false
    }
    return true
}

Upvotes: 2

James Henstridge
James Henstridge

Reputation: 43899

To determine the dynamic type of an interface variable, you can use the two-return form of a type assertion. For example, your isDog function could be implemented as:

func isDog(thing Animal) bool {
    _, isdog := thing.(packageName.Dog)
    _, isdogptr := thig.(*packageName.Dog)
    return isdog || isdogptr
}

Upvotes: 3

Related Questions