Can You Modify A Map's Values While
Fast recall
Quick revision
Core answer
Practical understanding of Range Over Slice Map.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
Three operations, three rules. Update existing values: safe and common — the iteration visits each key once, and writing to a key it has or hasn't reached yet is well-defined.
for k, v := range m {
m[k] = v * 2 // safe — updating existing entries
}Delete during range: safe — entries deleted before the iterator reaches them may or may not be visited (unspecified, but not a crash), and deletion never invalidates iteration:
for k := range m {
if expired(k) {
delete(m, k) // safe
}
}Add new keys: unspecified — the iterator may or may not visit entries added during the loop, and it's easy to construct an infinite loop (adding while iterating reaching the new entries, adding again). The GC-safe rule everyone uses: don't insert during range; if you must, collect the new keys first and insert after the loop.
The mental model: range takes a snapshot of the iteration mechanics, not the contents. Mutation of values stays consistent; structural changes (delete) are tolerated with relaxed promises; growth (insert) is where the runtime refuses to promise anything.
Can You Modify A Map's Values While
Direct Answer
Yes — updating existing keys during range is allowed. Adding new keys during iteration is unspecified; deleting is safe.
Deep Dive & Architecture
The rules differ because the operations differ. Updating m[k] inside range m doesn't restructure anything — the key exists, the value slot exists, the write is just a store. The iterator is walking buckets, and stores to existing entries don't move them.
Deletion during iteration is tolerated with a relaxed contract: entries deleted ahead of the iterator's position may or may not be visited — the spec says unspecified, meaning 'the runtime may differ, don't depend on it.' What's guaranteed: no crash, no corruption, and entries that exist and aren't deleted will all be seen. The cleanup loop pattern (range + delete expired) is standard idiom precisely because those guarantees are enough.
Insertion is where the runtime refuses to promise anything at all: a new key may land in a bucket the iterator already passed (never visited) or hasn't reached (may be visited) — and with growth, the iterator might follow a growing structure indefinitely. An infinite loop is constructible, and the code that has one looks innocent:
for k := range m {
m[k+"-new"] = process(m[k]) // adds keys forever in the worst shapes
}
The fix pattern: collect the additions, apply them after the loop — two passes, deterministic, and the intent is visible in the shape.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Range Over Slice Map, and when would you use it?
- How would you compare Range Over Slice Map with an alternative?
- What is a common mistake when using Range Over Slice Map?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.