Which types are comparable in Go, and when does comparing values panic at run time?
Question 25HardGo 1.22 to 1.25
Comparable types (== and != work): booleans, numbers, strings, pointers, channels, interfaces, arrays of comparable elements, and structs whose fields are all comparable.
Not comparable: slices, maps and functions. They can only be compared to nil. Map keys must be comparable types.
Interfaces are the trap. An interface type is comparable at compile time, but comparing two interfaces whose dynamic types are the same and not comparable panics at run time.
var a, b any = []int{1}, []int{1}
fmt.Println(a == b) // panic: runtime error: comparing uncomparable type []int
var c, d any = []int{1}, "x"
fmt.Println(c == d) // false: dynamic types differ, so no panic
m := map[any]int{}
m[[]int{1}] = 1 // panic: runtime error: hash of unhashable type []int
type Key struct {
Name string
Tags []string
}
// _ = map[Key]int{} // compile error: invalid map key type Key
Other rules:
- Pointers are equal when they point to the same variable. Pointers to two distinct zero-size variables may or may not be equal.
- Channels are equal when they come from the same
make. - Function values can't be compared at all, not even through
reflect(DeepEqualsays they're equal only if both are nil).
Tools for types that aren't comparable: slices.Equal, maps.Equal, bytes.Equal, reflect.DeepEqual (slow), and github.com/google/go-cmp in tests.
More on Language Fundamentals & Types
- Q23What restrictions does Go place on
goto? - Q24How does
switchdiffer from C, and what does thisfallthroughexample print? - Q26How does struct and array equality work? What is surprising about NaN as a map key?
- Q27What does the
comparableconstraint mean in generics, and what changed in Go 1.20? - Q28Explain method sets. Why does
var s Speaker = Dog{}fail to compile? - Q29What is addressability, and why can't you call a pointer method on a map element?