The comparable Constraint
Using comparable
Constraining a type parameter with the built-in comparable interface guarantees that == and != can be used on values of that type inside the generic function.
Example: Using comparable
package main
import "fmt"
func Contains[T comparable](items []T, target T) bool {
for _, item := range items {
if item == target {
return true
}
}
return false
}
func main() {
fmt.Println(Contains([]int{1, 2, 3}, 2))
fmt.Println(Contains([]string{"a", "b"}, "c"))
}
Login to try C/C++/Java/PHP code in the editor
comparable for Map Keys
Because Go map keys must be comparable, a generic function that builds a map keyed by its type parameter has to constrain that parameter with comparable, or the compiler rejects it.
Example: comparable for Map Keys
package main
import "fmt"
func CountOccurrences[T comparable](items []T) map[T]int {
counts := make(map[T]int)
for _, item := range items {
counts[item]++
}
return counts
}
func main() {
fmt.Println(CountOccurrences([]string{"a", "b", "a", "c", "b", "a"}))
}
Login to try C/C++/Java/PHP code in the editor
comparable Does Not Mean Ordered
comparable only guarantees equality checks (==, !=) -- it says nothing about whether values can be ordered with < or >, so a generic sort or Max function needs a different, more specific constraint.
Note: Use a union-based constraint like 'int | float64 | string' when you need <, >, <=, >= instead of comparable.
Example: comparable Does Not Mean Ordered
package main
import "fmt"
func Unique[T comparable](items []T) []T {
seen := make(map[T]bool)
var result []T
for _, item := range items {
if !seen[item] {
seen[item] = true
result = append(result, item)
}
}
return result
}
func main() {
fmt.Println(Unique([]int{1, 2, 2, 3, 1, 4}))
}
Login to try C/C++/Java/PHP code in the editor
- Trying to use comparable with a slice or map type parameter, since slices and maps are not themselves comparable in Go.
- Forgetting comparable only guarantees == and != work -- it says nothing about ordering (<, >), which needs a different constraint.
- Writing a generic function that needs a type as a map key without constraining it to comparable, causing a compile error.
- The built-in comparable constraint allows a type parameter to be compared with == and !=.
- comparable is required when a type parameter is used as a map key.
- Not every type is comparable -- slices, maps, and functions are excluded.
- comparable does not imply ordering; use a separate constraint (like Ordered) for < and >.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: