Maps: sets & nested maps
Maps are Go's unordered key/value tables, and with a few patterns — the empty-struct set, the comma-ok check, sorted-key printing, and nested maps — you can model membership, deduplication, and grouped data cleanly.
Learn Maps: sets & nested maps in our free Go course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ Sets with map[T]struct{' '}
Go has no set type, so you use a map. The idiomatic set is map[T]struct{' '}{' '} — the empty struct value occupies zero bytes , so only the keys matter. Add with seen[x] = struct{' '}{' '} , and test membership with the comma-ok form so you don't accidentally insert. This is the standard way to deduplicate or track "have I seen this before?".
2️⃣ Unordered Iteration & Deleting While Ranging
Map iteration order is deliberately randomized , so never depend on it. To produce deterministic output, collect the keys into a slice, sort them, and range the sorted keys. The good news: it is safe to delete the current (or already-seen) entry while ranging the same map — a common way to filter in place.
3️⃣ Nested Maps & the maps Package
A nested map ( map[string]map[string]int ) groups data two levels deep. The catch: an inner map starts as nil , and writing to a nil map panics — so initialize the inner map before assigning into it. Since Go 1.21 the maps package adds helpers like maps.Keys (an iterator), which pairs nicely with slices.Sorted to get sorted keys in one line.
🎯 Your Turn
Use comma-ok to distinguish "stored value is 0" from "key is missing". Fill in the two blanks.
Count how often each word appears, then print the words in sorted order with their counts. Split with strings.Fields , tally with counts[w]++ , and sort the keys before printing.
Practice quiz
How do you model a set of strings idiomatically in Go?
map[string]struct{} stores keys with zero-byte values, the idiomatic Go set.
Which form distinguishes a missing key from a stored zero value?
The comma-ok form v, ok := m[k] returns ok=false when the key is absent.
What happens to iteration order when you range over a map?
- Sorted ascending
- Insertion order
- Random / unspecified
- Sorted descending
Answer: Random / unspecified. Go deliberately randomizes map iteration order; sort the keys for deterministic output.
Is deleting the current key safe while ranging over a map?
- No, it panics
- Yes, it is safe
- Only with a lock
- Only for string keys
Answer: Yes, it is safe. Deleting entries during a range is explicitly safe in Go.
Is adding new keys safe while ranging over a map?
- Always safe
- Not guaranteed — they may or may not be visited
- Panics immediately
- Adds them to the front
Answer: Not guaranteed — they may or may not be visited. Adding keys during iteration is unspecified — added entries may or may not appear.
What does writing to a nil map do?
- Creates the map
- Panics at runtime
- Silently ignores
- Returns an error
Answer: Panics at runtime. Writing to a nil (uninitialized) map panics; you must make/initialize it first.
Before writing into an inner map of a nested map, you must:
- Nothing special
- Initialize that inner map first
- Lock the outer map
- Sort the keys
Answer: Initialize that inner map first. Each inner map is nil until created, so initialize it before assigning into it.
Which combination gives sorted keys from a map in modern Go?
- maps.Keys + slices.Sorted
- sort.Map
- map.Sort()
- keys.Order()
Answer: maps.Keys + slices.Sorted. maps.Keys yields the keys and slices.Sorted collects them in sorted order.
What does delete(m, k) do when k is not in the map?
- Panics
- Adds k
- Does nothing
- Returns an error
Answer: Does nothing. delete is a no-op when the key is absent — no panic, no error.
Reading a missing nested key like m["a"]["b"] when m["a"] exists returns:
- A panic
- The value's zero value
- An error
- nil only
Answer: The value's zero value. Reading a missing key returns the value type's zero value, so it is safe.