Go

How does struct and array equality work? What is surprising about NaN as a map key?

Question 26HardGo 1.22 to 1.25

Two struct values are equal when every field is equal, compared in the order the fields are declared. Unexported fields are compared too. Blank (_) fields are skipped. Padding bytes are never compared. Arrays are equal when every element is equal. Both are compared by value, which is why a [32]byte hash or a small struct makes a good map key.

type Point struct{ X, Y int }
fmt.Println(Point{1, 2} == Point{1, 2}) // true
fmt.Println([2]int{1, 2} == [2]int{1, 2}) // true

// Anonymous struct types with the same fields are assignable and comparable:
p := struct{ X, Y int }{1, 2}
fmt.Println(p == Point{1, 2}) // true

// NaN is never equal to itself:
nan := math.NaN()
fmt.Println(nan == nan) // false

m := map[float64]int{}
m[nan] = 1
m[nan] = 2
fmt.Println(len(m))     // 2: two entries that can never be looked up
_, ok := m[nan]
fmt.Println(ok)         // false
delete(m, nan)          // removes nothing
clear(m)                // Go 1.21: the only way to remove NaN keys
fmt.Println(len(m))     // 0

Gotchas:

  • A struct with a pointer field compares the addresses, not the values they point to.
  • A struct with an interface field can panic on == if the interface holds a slice.
  • Adding a slice or map field to a struct used as a map key breaks compilation. Adding a _ [0]func() field is a known trick to make a struct deliberately non-comparable.
  • +0.0 == -0.0 is true, so both map to the same key.

More on Language Fundamentals & Types

All 39 Language Fundamentals & Types questions