Maps
Maps are Go's built-in associative data type, also known as hash tables or dictionaries in other languages. Maps store key-value pairs.
Key Points
- Maps must be initialized with
makeor a literal before use - Accessing a non-existent key returns the zero value of the value type
- Use the comma-ok idiom to distinguish between zero values and missing keys
- Map iteration order is randomized for security reasons
- Maps are reference types - passing a map doesn't copy its contents
- Maps are not safe for concurrent use without synchronization
- Key types must be comparable - slices, maps, and functions cannot be keys
Creating and Using Maps
Maps must be initialized before use with make or a map literal:
package main
import "fmt"
func main() {
// Create a map with make
m := make(map[string]int)
// Set key-value pairs
m["k1"] = 7
m["k2"] = 13
fmt.Println("map:", m)
// Get a value
v1 := m["k1"]
fmt.Println("v1:", v1)
// len returns number of key-value pairs
fmt.Println("len:", len(m))
// Delete a key-value pair
delete(m, "k2")
fmt.Println("map:", m)
}map: map[k1:7 k2:13]
v1: 7
len: 2
map: map[k1:7]Checking Key Existence
The optional second return value indicates if the key was present:
package main
import "fmt"
func main() {
m := map[string]int{"foo": 1, "bar": 2}
// Check if key exists
v, exists := m["foo"]
fmt.Println("foo exists:", exists, "value:", v)
v, exists = m["baz"]
fmt.Println("baz exists:", exists, "value:", v)
// Common idiom
if val, ok := m["foo"]; ok {
fmt.Println("Found:", val)
}
}foo exists: true value: 1
baz exists: false value: 0
Found: 1Map Literals
You can declare and initialize a map in one line:
package main
import "fmt"
func main() {
// Initialize with values
n := map[string]int{
"foo": 1,
"bar": 2,
}
fmt.Println("map:", n)
// Empty map literal
empty := map[string]int{}
fmt.Println("empty:", empty)
}map: map[bar:2 foo:1]
empty: map[]Iterating Over Maps
Use range to iterate over key-value pairs:
package main
import "fmt"
func main() {
m := map[string]string{
"a": "alpha",
"b": "beta",
}
// Iterate over key-value pairs
for k, v := range m {
fmt.Printf("%s -> %s\n", k, v)
}
// Iterate over keys only
for k := range m {
fmt.Println("key:", k)
}
}a -> alpha
b -> beta
key: a
key: bMap Declaration Patterns
| Pattern | Example | Description |
|---|---|---|
make(map[K]V) | make(map[string]int) | Create empty map |
make(map[K]V, size) | make(map[string]int, 10) | Create map with initial capacity hint |
map[K]V{} | map[string]int{} | Empty map literal |
map[K]V{k:v, ...} | map[string]int{"a":1, "b":2} | Map literal with initial values |
var m map[K]V | var m map[string]int | Declare nil map (must init before use) |
Map Operations
| Operation | Syntax | Example | Description |
|---|---|---|---|
| Set value | m[key] = value | m["x"] = 10 | Add or update key-value pair |
| Get value | v := m[key] | v := m["x"] | Retrieve value (zero value if not exists) |
| Check existence | v, ok := m[key] | v, ok := m["x"] | Get value and existence check |
| Delete | delete(m, key) | delete(m, "x") | Remove key-value pair |
| Length | len(m) | len(m) | Number of key-value pairs |
| Iterate | for k, v := range m | for k, v := range m | Loop through all pairs |
| Clear (Go 1.21+) | clear(m) | clear(m) | Remove all key-value pairs |
Map Key Types
| Category | Types | Notes |
|---|---|---|
| Comparable types | bool, int, float, string, pointer, channel, interface, array | Can be used as map keys |
| Non-comparable | slice, map, function | Cannot be used as map keys |
| Struct keys | Structs with comparable fields | Must have all comparable fields |
| Array keys | Arrays with comparable elements | Size is part of type |
Map Characteristics
| Feature | Behavior | Notes |
|---|---|---|
| Order | Unordered | Iteration order is random |
| Reference type | Passed by reference | Modifications visible to caller |
| Zero value | nil | Nil maps cannot be written to |
| Thread safety | Not safe | Use sync.Map or mutex for concurrency |
| Missing keys | Return zero value | Use comma-ok idiom to check |
| Deletion | Safe during iteration | Can delete while ranging |
Common Patterns
| Pattern | Code | Use Case |
|---|---|---|
| Set data structure | map[T]bool or map[T]struct{} | Check membership efficiently |
| Count occurrences | counts[item]++; // works even if key doesn't exist | Frequency counting |
| Group by key | map[K][]V | Group values by category |
| Check and set | if _, ok := m[k]; !ok { m[k] = v } | Set only if key doesn't exist |
| Default value | if v, ok := m[k]; ok { return v } else { return defaultVal } | Get with fallback |
| Nested maps | map[K1]map[K2]V | Multi-level lookup |