A Go map holds distinct keys and their values without promising an order. It is backed by a hash table: a hash function directs each key to a bucket, where Go looks for the matching key. Not every type can be a key; a slice, for example, cannot. section 3.11.1 section 12.6.2
Size a map before a large insertion
Starting with a small map and adding a million entries makes it grow and redistribute keys. If the expected count is known, write `m := make(map[string]int, 1_000_000)`. The number is a sizing hint, not a maximum: more entries can still be added. This avoids much of the work of creating and reorganizing buckets during insertion. Use the hint when the expected count is reasonably known, rather than treating every map as fixed-size. section 3.11.2
Deletion does not give buckets back
A map can retain substantial memory after its entries are deleted. In a measured `map[int][128]byte`, adding one million entries raised heap use to 461 MB; deleting them and running garbage collection left 293 MB. Deletion clears slots, but the bucket count does not shrink. In the same comparison, `map[int]*[128]byte` left 38 MB after deletion and collection. Pointer values can therefore change the memory trade-off, but deleting entries alone is not a way to shrink the map's buckets. section 3.12
Do not use range as an ordering rule
`for k := range m { fmt.Print(k) }` does not print keys in sorted, insertion, or bucket-storage order. Even two traversals of the same map can differ. The iteration order is unspecified—not a source of uniform randomness—so code that needs an order must not infer one from a map traversal. section 4.4.1
A map assignment is not a protected snapshot
Suppose a balance cache has `balances map[string]float64` guarded by `sync.RWMutex`. Locking only long enough to run `balances := c.balances`, then ranging over `balances` after unlocking, still races with a goroutine updating the cache: the assignment refers to the same buckets. For a short traversal, hold the read lock throughout it. If the traversal should run outside the lock, create another map and copy its entries while locked. A test run with `-race` exposes the faulty version. section 9.10
Two boundary cases are worth checking:
- For uncertain JSON fields, `json.Unmarshal` can fill a `map[string]any`, but a numeric field such as `"id": 32` becomes `float64`, not `int`. section 10.3.3
- For a `[]byte` lookup key, use a string key type. A direct lookup such as `m[string(bytes)]` receives a compiler optimization that the shown intermediate `key := string(bytes); m[key]` version does not. section 12.6.2









































