Maps in Go
By Syncfusion®, Inc. · Last updated
Go maps: key-value pairs. Create them with literals and make, add, update, delete and look up values, check keys with comma-ok, loop with range, and use zero values and nested maps.
What Are Maps?
Map = a collection of key and value pairs, where you find a value by its key.
- Key = the label you look up, like a student's name.
- Value = what is stored for that key, like their marks.
- Every key is unique. One key has one value.
Simple lesson: a map stores values by name, so you can find any value straight away.
A Real-World Example
Think of the school's phone directory.
- Each line has a name and a phone number.
- To call the principal, you look for "Principal", not for line number 17.
- Each name appears only once.
- New names can be added, old ones changed or removed.
Now the mapping:
- The directory = the map.
- The name = the key.
- The phone number = the value.
- Looking up a name =
directory["Principal"].
Slices find values by position: marks[2].
Maps find values by key: marks["Asha"].
Use a map when you think "look up X by its name".
What You Will Learn
In this lesson, you will learn:
- What maps and key-value pairs are.
- How to create maps with a literal or with
make(). - How to add, update, delete and look up values.
- How to check if a key exists with the comma-ok idiom.
- How to loop over a map with
range. - Map best practices: zero values and nested maps.
Map Fundamentals
Key-Value Pairs
A map type is written map[KeyType]ValueType.
map[string]int= keys are strings, values are ints.map[int]string= keys are ints, values are strings.- Keys must be comparable with
==: strings, numbers, bools, arrays and simple structs work. Slices and maps cannot be keys.
Creating Maps
Ways to make a map
Create maps
package main
import "fmt"
func main() {
marks := map[string]int{
"Asha": 91,
"Ravi": 78,
}
rooms := make(map[string]string)
rooms["8A"] = "Room 12"
fmt.Println(marks)
fmt.Println(rooms, len(rooms))
}
map[Asha:91 Ravi:78]
map[8A:Room 12] 1
fmt.Printlnprints a map with its keys sorted, so the output is tidy.len(m)gives the number of pairs.
make()
make = build a ready-to-use map (or slice, or channel).
make(map[string]int)= an empty map.make(map[string]int, 100)= an empty map with room for about 100 pairs. It still grows if needed.
Simple lesson: write map[K]V{...} or make(map[K]V), then use keys to reach values.
Map Operations
Type a key and a value, then try every button.
Try these:
- Set a new name: a new pair is added.
- Set an existing name: its value is replaced.
- Look up a missing name: you get
0andok = false. - Delete a missing name: nothing happens, and there is no error.
Add and Update Elements
The same line adds or updates: m[key] = value.
Add and update
package main
import "fmt"
func main() {
stock := map[string]int{"pencils": 40}
stock["erasers"] = 25
stock["pencils"] = 35
stock["pencils"] += 10
fmt.Println(stock)
}
map[erasers:25 pencils:45]
"erasers"was new, so it is added."pencils"existed, so it is updated.+=works too: it reads, adds, then stores.
Lookup Values
Read values
package main
import "fmt"
func main() {
marks := map[string]int{"Asha": 91, "Ravi": 78}
fmt.Println(marks["Asha"])
fmt.Println(marks["Zoya"])
}
91
0
- A missing key gives the zero value of the value type:
0here. - There is no error. So
0could mean "scored 0" or "not in the map".
Delete Elements
delete() = remove a key and its value.
delete()
package main
import "fmt"
func main() {
club := map[string]string{"Asha": "8A", "Ravi": "8B", "Meena": "8A"}
delete(club, "Ravi")
delete(club, "Nobody")
fmt.Println(club, len(club))
}
map[Asha:8A Meena:8A] 2
delete(map, key)removes the pair.- Deleting a key that is not there is safe. Nothing happens.
Simple lesson: m[k] = v adds or updates, m[k] reads, and delete(m, k) removes.
Map Lookup
Comma-Ok Idiom
Comma-ok idiom = value, ok := m[key]. ok is true only if the key is really in the map.
Press Play to see both cases.
Is the student in the map?
Checking Key Existence
Check before you use
package main
import "fmt"
func main() {
rooms := map[string]string{"8A": "Room 12", "8B": "Room 14"}
if room, ok := rooms["8C"]; ok {
fmt.Println("8C is in", room)
} else {
fmt.Println("No room set for 8C")
}
_, has8A := rooms["8A"]
fmt.Println(has8A)
}
No room set for 8C
true
- The
ifwith a short statement keepsroomandokinside theif. See Conditional Statements. - Use
_when you only need to know if the key exists.
Simple lesson: use v, ok := m[k] to tell a real zero value from a missing key.
Map Iteration
range
range over a map gives each key and value.
Loop over a map
package main
import "fmt"
func main() {
fees := map[string]int{"Asha": 1500, "Ravi": 1200, "Meena": 1500}
total := 0
for _, fee := range fees {
total += fee
}
fmt.Println("Total fees:", total)
}
Total fees: 4200
The Order Changes
Go walks through a map in a random order, and the order changes from run to run.
Run this twice: the order may change
package main
import "fmt"
func main() {
houses := map[string]int{"Red": 120, "Blue": 95, "Green": 110, "Yellow": 101}
for house, points := range houses {
fmt.Println(house, points)
}
}
- Never depend on the order of a map loop.
- If you need an order, put the keys in a slice and sort it first.
Print in sorted order
package main
import (
"fmt"
"sort"
)
func main() {
houses := map[string]int{"Red": 120, "Blue": 95, "Green": 110}
names := make([]string, 0, len(houses))
for h := range houses {
names = append(names, h)
}
sort.Strings(names)
for _, h := range names {
fmt.Println(h, houses[h])
}
}
Blue 95
Green 110
Red 120
for h := range housesgives only the keys.sort.Stringsputs the keys in alphabetical order.
Simple lesson: range gives keys and values in a random order, so sort the keys when order matters.
Map Best Practices
Zero Values
The zero value makes counting easy: a missing key starts at 0.
Count votes for class monitor
package main
import "fmt"
func main() {
votes := []string{"Asha", "Ravi", "Asha", "Meena", "Asha", "Ravi"}
count := make(map[string]int)
for _, name := range votes {
count[name]++
}
fmt.Println(count)
}
map[Asha:3 Meena:1 Ravi:2]
count[name]++works even the first time, because a missing key reads as0.
Never Write to a nil Map
Writing to a nil map
package main
import "fmt"
func main() {
var marks map[string]int
fmt.Println(marks["Asha"])
marks["Asha"] = 91
}
- Reading from a nil map is fine: it gives
0. - Writing to it stops the program:
panic: assignment to entry in nil map. - Fix: create it first with
makeor{}.
Nested Maps
Nested map = a map whose values are maps.
Marks by class, then by student
package main
import "fmt"
func main() {
school := map[string]map[string]int{
"8A": {"Asha": 91, "Meena": 85},
"8B": {"Ravi": 78},
}
fmt.Println(school["8A"]["Meena"])
if school["8C"] == nil {
school["8C"] = make(map[string]int)
}
school["8C"]["Kabir"] = 94
fmt.Println(len(school), school["8C"])
}
85
3 map[Kabir:94]
school["8A"]["Meena"]reads the inner map, then the student.- Before writing into a new inner map, create it. Otherwise it is nil.
Maps are not safe for two goroutines writing at the same time.
You will learn how to protect them in Synchronization.
Easy way to remember
- Add or update:
m[k] = v - Safe lookup:
v, ok := m[k] - Remove:
delete(m, k) - Order: none. Sort the keys if you need one.
Simple lesson: use the zero value for counting, always create a map before writing, and create inner maps too.
TL;DR
- Map = key-value pairs:
map[string]int. Keys are unique. - Create =
map[K]V{...}ormake(map[K]V).var m map[K]Vis nil. Add / update =
m[k] = v. Read =m[k]. Remove =delete(m, k).- Length =
len(m).
- Length =
- Missing key = the zero value, no error.
- Comma-ok =
v, ok := m[k].oktells you if the key exists. - range =
for k, v := range m. The order is random. - Best practices = count with
m[k]++, never write to a nil map, create inner maps first.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
var m map[string]int then m["a"] = 1 | var makes an empty map | It makes a nil map | assignment to entry in nil map |
if m["Zoya"] == 0 to check a key | 0 means missing | 0 may be a real value | Wrong answers. Use comma-ok. |
| Relying on loop order | Maps keep insertion order | The order is random | Output changes run to run. |
map[[]int]string | Any type can be a key | Keys must be comparable | A build error. |
| Forgetting to create an inner map | Inner maps exist already | They start as nil | A panic on write. |
delete(m, k) and checking an error | It returns an error | It returns nothing | A build error. |
| Two goroutines writing one map | Maps are thread-safe | They are not | concurrent map writes crash. |
Check Yourself
Exercises
What to Remember
- A map stores values by key:
map[string]int. Keys are unique. - Create with a literal or
make. Never write to a nil map. m[k] = vadds or updates.delete(m, k)removes.- A missing key gives the zero value. Use
v, ok := m[k]to be sure. - Map loops have a random order. Sort the keys when you need one.
Next: Pointers. You will learn how a variable can point to another variable's box in memory.