
Why Are My Struct Fields Not Comparable with ==?
== on a struct walks every field. If any field's type is not comparable — slice, map, or function — the compiler rejects the comparison. A nil slice does not help; the type is what matters. That same rule is why the struct cannot be a map key.
The failure
package main
type User struct {
Name string
Tags []string
}
func main() {
a := User{Name: "Ada", Tags: []string{"go"}}
b := User{Name: "Ada", Tags: []string{"go"}}
_ = a == b // invalid operation: struct containing []string cannot be compared
}
Name is fine. Tags poisons the type.
m := map[User]int{} // invalid map key type User
Why this happens
Go's == is defined for a closed set of types: booleans, numbers, strings, pointers, channels, interfaces (with a runtime panic if the dynamic type is incomparable), arrays of comparable types, and structs whose every field is comparable. Nested structs recurse. Arrays are comparable; slices are not. Arrays have a fixed length baked into the type. Slices are a header over a backing array — equality would have to invent a policy for length, capacity, and shared backing memory. The language refuses rather than guess.
Pointers compare as addresses, not as the values they point at. Two *int fields are equal when they name the same variable, not when both *p and *q are 42.
Omitted fields in a composite literal are still zero values ("", 0, nil). User{Name: "Ada"} is not "undefined Tags"; Tags is a nil slice. Equality, when it is allowed, includes those zeros.
The fix
Compare the fields you mean:
func sameUser(a, b User) bool {
if a.Name != b.Name || len(a.Tags) != len(b.Tags) {
return false
}
for i := range a.Tags {
if a.Tags[i] != b.Tags[i] {
return false
}
}
return true
}
Or, in tests, reflect.DeepEqual(a, b) — it walks slices and maps. It is slower, has no compile-time check, and follows pointers. Use it in tests, not in a hot map lookup.
If the struct must be a map key, do not store a slice on it. Join tags into a string, use an array with a fixed max, or key by an ID:
type UserKey struct {
Name string
Tags string // strings.Join(tags, "\x00")
}
Keep the slice on a separate value type that you do not compare with ==.