Instead, define a type-set using an interface for use as a constraint:
type number interface { int | float64}
The | operator is only available in type constraints. It defines a set of allowed types for a type parameter.
Usage:
func add[T number](a T, b T) T { return a + b}
The | operator can also be used inline without declaring a named constraint:
func add[T int | float64](a T, b T) T { return a + b}
To include named types whose underlying type matches a constraint, use ~:
type number interface { ~int | ~float64}
~int means int and any named type with underlying type int.
type myInt intfunc add[T ~int | ~float64](a T, b T) T { return a + b}func main() { var a myInt = 5 var b myInt = 10 fmt.Println(add(a, b)) // 15}
Why?
Because in Go, named types are distinct from their underlying types, even if they share the same representation.
The ~ operator allows constraints to match based on the underlying type instead of only the exact type.
type myInt intfunc main() { var a myInt = 10 var b = 20 a = b // <-- compiler: cannot use b (variable of type int) as myInt value in assignment a = myInt(b) // <- ok (compatible for type casting) fmt.Println(a, b) // 20 20}
Examples:
func main() { fmt.Println(add(1, 2)) // 3 fmt.Println(add(1.5, 2.3)) // 3.8}func add[T int | float64](a T, b T) T { return a + b}
Without generics:
func main() { fmt.Println(addInts(1, 2)) // 3 fmt.Println(addFloats(1.5, 2.3)) // 3.8}func addInts(a, b int) int { return a + b}func addFloats(a, b float64) float64 { return a + b}