How to check if slice interface elements have the same dynamic type?

Issue

I have the following structs and they follow this structure:

A is the interface, and B, C, D are all types with interface A.

I have a slice of variables args all with type with interface A, each of which can be B, C, D type specifically.

I’d like to write a for loop to judge if all variables in the slice fall into the same dynamic type.

I wrote the following code:

var existingTyp A
for i, d := range args {
 switch typ := d.(type) {
   case *B, *C, *D:
    if existingTyp == nil {
        existingTyp = typ
    } else {
        if typ != existingTyp {
            panic("error!")
        }
   }
}

How to revise the code to achieve what I want?

Solution

You can’t use the equality operator == on the interface values. Even if the dynamic types are the same, the comparison may return false if they have fields with different values. Or it panics if B, C and D aren’t comparable to begin with.

Instead you can use reflection and use == on reflect.Type. This solution doesn’t require you to update the code if you add more types that implement A.

func dynamicTypesEq(args []A) bool {
    var a reflect.Type
    for _, d := range args {
        t := reflect.TypeOf(d)
        if a == nil {
            a = t
            continue
        }
        if a != t {
            return false
        }

    }
    return true
}

Calling the function with some example slices:

func main() {
    a := []A{&B{}, &B{}, &B{}}
    fmt.Println(dynamicTypesEq(a)) // true

    b := []A{&C{}, &B{}, &B{}}
    fmt.Println(dynamicTypesEq(b)) // false


    c := []A{&D{}, &D{}, &B{}}
    fmt.Println(dynamicTypesEq(c)) // false
}

Note that this function reports false in case the input has *B and B. Clearly, a pointer type is not the same as the base type.

Playground: https://go.dev/play/p/QOCvSyxGPRU

Answered By – blackgreen

Answer Checked By – David Goodson (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.