Go Type Sets
A type set is the group of types a constraint allows. A generic function can name a whole set at once instead of naming one fixed type.
The same job written twice
Two copies of Double do the same job for two types. Each new type would need another copy.
package main
import "fmt"
func DoubleInt(n int) int {
return n * 2
}
func DoubleFloat(f float64) float64 {
return f * 2
}
func main() {
fmt.Println(DoubleInt(21))
fmt.Println(DoubleFloat(2.5))
}One function over a type set
The Number constraint lists int and float64 with a | sign. The ~ sign lets the named type Degrees in through its underlying float64 type.
package main
import "fmt"
type Number interface {
~int | ~float64
}
type Degrees float64
func Double[T Number](v T) T {
return v * 2
}
func main() {
fmt.Println(Double(21))
fmt.Println(Double(2.5))
fmt.Println(Double(Degrees(15)))
}A constraint that demands a method
The Ordered constraint demands a Compare method. Score has that method, so Max can pick the larger of two scores.
package main
import "fmt"
type Ordered[T any] interface {
Compare(T) int
}
type Score int
func (s Score) Compare(other Score) int {
if s < other {
return -1
}
if s > other {
return 1
}
return 0
}
func Max[T Ordered[T]](a, b T) T {
if a.Compare(b) >= 0 {
return a
}
return b
}
func main() {
fmt.Println(Max(Score(7), Score(12)))
fmt.Println(Max(Score(20), Score(9)))
}Example
package main
import "fmt"
type Number interface {
~int | ~float64
}
func Sum[T Number](values []T) T {
var total T
for _, v := range values {
total += v
}
return total
}
func main() {
fmt.Println(Sum([]int{1, 2, 3}))
fmt.Println(Sum([]float64{1.5, 2.5}))
}Key points
- A constraint can list several types with the | sign.
- The ~ sign in a constraint means the underlying type, so named types join the set.
- One generic function over a type set serves every type in the set.
- A constraint can also demand a method, and only types with that method fit.
- The Ordered constraint uses T inside itself, so a type must compare against its own kind.
In this example, Sum takes a slice of any type in the Number set. The first call adds ints and prints 6. The second call adds float64 values and prints 4, with no second copy of the function.
Note
A value outside the set is refused at compile time.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Go Playground
Exercise
What does the ~ sign do in a constraint?