Why can't you compare slices with ==? How do you check equality of slices, maps, and structs containing them?
Question 51MediumGo 1.22 to 1.25
Slices, maps, and functions are not comparable. You can compare them only to nil. The language designers left out == for slices on purpose, because it is ambiguous: shallow (same backing array) or deep (same elements)? The deep version would also need to handle cycles and could be expensive without anyone noticing. So any struct with a slice field is also not comparable and cannot be a map key.
a := []int{1, 2, 3}
b := []int{1, 2, 3}
// fmt.Println(a == b) // compile error: slice can only be compared to nil
fmt.Println(slices.Equal(a, b)) // true
fmt.Println(bytes.Equal([]byte("x"), nil)) // false; bytes.Equal(nil, []byte{}) is true
m1 := map[string]int{"a": 1}
m2 := map[string]int{"a": 1}
fmt.Println(maps.Equal(m1, m2)) // true
type T struct{ Tags []string }
// map[T]int{} // compile error: invalid map key type T
// Generic custom equality
eq := slices.EqualFunc(a, b, func(x, y int) bool { return x == y })
_ = eq
Gotchas:
reflect.DeepEqualis slow and treats nil and empty as different.- Comparing interface values that hold slices compiles, but panics at run time:
any([]int{}) == any([]int{})fails with "comparing uncomparable type []int". - In tests, prefer
github.com/google/go-cmp/cmp.Difffor readable output.
More on Arrays, Slices, Maps & Strings
- Q49How can subslicing cause memory leaks, and how do you fix them?
- Q50How do you delete elements from a slice efficiently, and what changed with slices.Delete in Go 1.22?
- Q52How do you correctly allocate a 2D slice, and what are the performance trade-offs?
- Q53Why do the slices package functions use the constraint [S ~[]E, E any] instead of just []E?
- Q54Which slices and maps package functions do you use daily, and how do they work with iterators (Go 1.23)?
- Q55Describe how Go maps were implemented before Go 1.24 (buckets, tophash, load factor, growth).