Why does m["k"].Field = 1 fail to compile for map[string]T where T is a struct?
Question 61MediumGo 1.22 to 1.25
Map elements are not addressable. m["k"] gives you a copy of the value, and assigning to a field of a temporary copy would do nothing. So the compiler rejects it: cannot assign to struct field m["k"].Field in map. The same rule blocks m[k][0] = x when the value is an array type. It also blocks calling pointer-receiver methods on the value: m[k].PtrMethod() fails with "cannot call pointer method PtrMethod on T", because the compiler cannot take the address of m[k].
type Point struct{ X, Y int }
m := map[string]Point{"a": {1, 2}}
// m["a"].X = 10 // compile error
// Fix 1: copy, modify, write back
p := m["a"]
p.X = 10
m["a"] = p
// Fix 2: store pointers
mp := map[string]*Point{"a": {1, 2}}
mp["a"].X = 10 // OK: modifies the pointee
// but beware: mp["missing"].X panics (nil pointer dereference)
// These DO work:
counts := map[string]int{}
counts["x"]++ // m[k] op= v is allowed (read-modify-write)
lists := map[string][]int{"a": {0}}
lists["a"][0] = 5 // OK: slice element is addressable via the header's pointer
Trade-off: map[K]*V allows in-place updates and avoids copying large values, but costs one allocation per value, adds GC scanning work, and lets callers who hold the pointer share mutable state. map[K]V is better for small value types.
More on Arrays, Slices, Maps & Strings
- Q59What happens when multiple goroutines access a map concurrently? How do you make it safe?
- Q60When should you use sync.Map instead of a map with a mutex?
- Q62Why can't you take the address of a map element (&m[k]), when you can with slice elements?
- Q63Which types can be map keys? What happens with interface keys and NaN?
- Q64Do Go maps shrink after deleting entries? How do you reclaim memory?
- Q65What does the built-in clear() do for slices vs maps?