Go

When does comparing two interface values panic? What does this print?

Question 99HardGo 1.22 to 1.25

Two interface values are equal when their dynamic types are identical and their dynamic values are equal, or when both are nil. If the dynamic types are the same and that type is not comparable (slice, map, func, or a struct or array containing one), the comparison panics at runtime. It compiles fine, because the compiler cannot know the dynamic type.

var a, b any = 1, 1
fmt.Println(a == b)            // true

var c, d any = 1, int64(1)
fmt.Println(c == d)            // false: different dynamic types, no panic

var e, f any = []int{1}, "x"
fmt.Println(e == f)            // false: types differ, values never compared

var g, h any = []int{1}, []int{1}
fmt.Println(g == h)            // panic: runtime error: comparing uncomparable type []int

m := map[any]bool{}
m[[]int{1}] = true             // panic: runtime error: hash of unhashable type []int

type S struct{ tags []string }
var x, y error = nil, nil
_ = x == y                     // true
var s1, s2 any = S{}, S{}
_ = s1 == s2                   // panic: comparing uncomparable type main.S

This matters in practice:

  • A typed error defined as a struct with a slice field makes err == ErrX or errors.Is panic if both sides hold that type. errors.Is guards against this with a comparability check. Hand-written == comparisons do not.
  • Generic code with the comparable constraint accepts interface types (Go 1.20+), so == in generic code can also panic at runtime.

reflect.DeepEqual avoids the panic, or you can check reflect.TypeOf(x).Comparable() before using ==. slices.Equal on a []any does not help: it uses == on each element and panics the same way.

More on Interfaces, Methods & Embedding

All 35 Interfaces, Methods & Embedding questions