'is there a Generic way to assert type? [duplicate]

I have found myself writing the same function X number of times to get different types of Items out of my go-cache. The duplicate functions are like so:

func TCPChecks() []*TCPCheck {
    var result []*TCPCheck
    for _, item := range Cache.Items() {
        if check, ok := item.Object.(*TCPCheck); ok {
            result = append(result, check)
        }
    }
    return result
}

func HTTPChecks() []*HTTPCheck {
    var result []*HTTPCheck
    for _, item := range Cache.Items() {
        if check, ok := item.Object.(*HTTPCheck); ok {
            result = append(result, check)
        }
    }
    return result
}

func VersionChecks() []*VersionCheck {
    var result []*VersionCheck
    for _, item := range Cache.Items() {
        if check, ok := item.Object.(*VersionCheck); ok {
            result = append(result, check)
        }
    }
    return result
}

func PodChecks() []*PodCheck {
    var result []*PodCheck
    for _, item := range Cache.Items() {
        if check, ok := item.Object.(*PodCheck); ok {
            result = append(result, check)
        }
    }
    return result
}

I'm sure im doing things wrong in General but I'm still in the experimental stage and having a play.

My question:

is there a way to write a function such that I can say

func ChecksByType(t Type) []*Check {
    var result []*Check
    for _, item := range Cache.Items() {
        if check, ok := item.Object.(t); ok {
            result = append(result, check)
        }
    }
    return result
}

ChecksByType(*PodCheck)

My previous attempts result in the error

t is not a type

which I understand. I don't understand how to remove this duplication and have a generic function.



Solution 1:[1]

Go 1.18 finally introduced generics, and you can write a single function that gathers values of any type.

This is how it could look like:

func Checks[T any]() []T {
    var result []T
    for _, item := range Cache.Items() {
        if check, ok := item.Object(T); ok {
            result = append(result, check)
        }
    }
    return result
}

Also note that since generics are now supported, the Cache itself can likely be re-written to support generics too.

Original answer follows.


Go does not have generics, so what you want is not possible. If this really bothers you, you could use reflection to pass in the reflect.Type of the values you want, use reflection to create and assemble that result slice, but it'll be slower than your individual functions.

You could also use a type switch to reduce the code repetition, but you cannot have "dynamic" return type. So the caller would still have to use a type assertion on the return value.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1