← Back to Go Course | Chapter 12: Generics | Lesson 6 of 6

The comparable Constraint

The comparable constraint is Go's way of saying 'this type must support checking if two values are exactly equal', which is required for things like map keys.

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

markup
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"))
}

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

markup
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"}))
}

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

markup
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}))
}
Common Mistakes
  1. Trying to use comparable with a slice or map type parameter, since slices and maps are not themselves comparable in Go.
  2. Forgetting comparable only guarantees == and != work -- it says nothing about ordering (<, >), which needs a different constraint.
  3. Writing a generic function that needs a type as a map key without constraining it to comparable, causing a compile error.
Chapter Summary
  • 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:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.