Search code examples
functiongogenericsinterfaceconstraints

Is it possible to write a constraint to exclude a type?


type NonString interface {
    // ???
}

func MyFunc[T NonString](v T) T {
    return v
}

func main() {
    MyFunc(1)          // OK
    MyFunc(false)      // OK
    MyFunc([]string{}) // OK

    MyFunc("hi, boy!") // I hope a comiler error occurs here!  
}

What I want is decribed in the comments of the code above.

Is it possible in golang?


Original Scenario

I have two functions as follows:

func Any2String(v any) string {        
    return fmt.Sprint(v) // Slow version
}

func Integer2String[N Integer](v N) string {
    return strconv.FormatInt(int64(v), 10) // Fast version
}

Any2String(v) can convert any v to a string. However, if v is an integer, Integer2String(v) is much more faster.

So, I want the compiler to PREVENT me from calling Any2String(v) when the faster Integer2String(v) is applicable.


Solution

  • No, it's not possible. Constraint type sets cannot be expressed as set subtraction.

    It is possible to define constraints that can't be satisfied by any type, for example:

    type NotSatisfiable interface {
        int
        foo()
    }
    

    This constraint mandates a type that is exactly int and that has a method foo(). Since you can't define methods on predeclared types, it's not possible to satisfy this constraint.

    However you can't define a constraint like "any-minus-int" or "any-plus-NotSatisfiable".

    If you have a function that works exactly the same for any type except a discrete number of types, just use a type switch:

    func ToString(v any) string {
        switch t := v.(type) {
        case int:
            return Integer2String(t)
        default:
            return Any2String(t)
        }
    }
    

    You don't even need generics, because a regular argument of type any works just fine.