This compiles. Why does it panic at runtime?
var a, b any = []int{1}, []int{1}
fmt.Println(a == b)
// panic: runtime error: comparing uncomparable type []int
seen := map[any]bool{}
seen[[]int{1}] = true
// panic: runtime error: hash of unhashable type []int
Comparing two interface values is allowed at compile time. At runtime, Go first compares the dynamic types. If they are the same and that type is not comparable (slice, map, func, or a struct or array containing one), it panics. Using such a value as a key in a map[any]T panics for the same reason: it has to be hashed.
A subtle point: if the dynamic types differ, the result is simply false with no panic, so the bug appears only for some inputs. This regularly hits caches keyed by any, dedup helpers, and hand-written err == target checks on custom error types that contain slices. errors.Is itself is safe, because it uses == only when the target's type is comparable. For such a type it simply never matches, so give the error an Is method.
With generics, the comparable constraint used to exclude interface types. Since Go 1.20, interfaces satisfy comparable, so func Eq[T comparable](a, b T) bool called with any can panic in the same way. Safer options: reflect.DeepEqual, slices.Equal, or a type switch that rejects kinds that cannot be compared.
More on Tricky Output & Code-Review Puzzles
- Q506Why do these two floating-point comparisons give different results?
- Q507What does indexing and ranging over a UTF-8 string print?
- Q509Why does errors.Is return different results here?
- Q510Go 1.23 range-over-func: what does this buggy iterator do?
- Q511What does this counter print, and how do you prove the bug?
- Q512Deleting from a slice in place: what do both lines print?