Maps

Overview

Maps are Go’s built-in hash table type, providing O(1) average-time lookups, insertions, and deletions.

Creating Maps

var m map[string]int           // nil map (read-only!)
m := make(map[string]int)      // Empty, ready to use
m := make(map[string]int, 100) // With capacity hint
m := map[string]int{           // Literal
    "one": 1,
    "two": 2,
}

Basic Operations

Set

m["key"] = value

Get

val := m["key"]  // Returns zero value if missing

Delete

delete(m, "key")  // No-op if key doesn't exist

Check Existence

val, ok := m["key"]
if ok {
    // Key exists
}

if _, exists := m["key"]; exists {
    // Key exists
}

nil Map Behavior

var m map[string]int  // nil

val := m["key"]       // OK: returns 0
m["key"] = 1          // PANIC! Cannot write to nil map

Always initialize before writing:

m := make(map[string]int)
m["key"] = 1  // OK

Iteration

for key, value := range m {
    fmt.Printf("%s: %d\n", key, value)
}

for key := range m {  // Keys only
    fmt.Println(key)
}

Warning: Iteration order is randomized!

Common Patterns

Set (Unique Values)

set := make(map[string]struct{})
set["item"] = struct{}{}
if _, exists := set["item"]; exists {
    // Item is in set
}
delete(set, "item")

Counter

counter := make(map[string]int)
for _, word := range words {
    counter[word]++  // Zero value works!
}

Grouping

groups := make(map[string][]User)
for _, user := range users {
    groups[user.Country] = append(groups[user.Country], user)
}

Default Value

val := m["key"]
if val == 0 {
    val = defaultValue
}

Concurrency Warning

Maps are not goroutine-safe:

// Unsafe: concurrent read/write
go func() { m["key"] = 1 }()
go func() { _ = m["key"] }()

// Use sync.Map or mutex
var mu sync.Mutex
mu.Lock()
m["key"] = 1
mu.Unlock()

The maps Package (Go 1.21+)

The standard library maps package provides generic utilities for common operations.

import "maps"

maps.Clone(m)                 // Shallow copy
maps.Equal(m1, m2)            // Compare
maps.DeleteFunc(m, func(k K, v V) bool {
    return v < 10             // Conditional delete
})

Modern Loop Pattern (Go 1.23+)

Using iterators with maps:

for k, v := range maps.All(m) { /* ... */ }
for k := range maps.Keys(m) { /* ... */ }
for v := range maps.Values(m) { /* ... */ }

Map Internals

  • Keys must be comparable (== must work)
  • Valid key types: bool, numeric, string, pointer, channel, interface, structs/arrays of comparable types
  • Invalid: slices, maps, functions

Summary

Operation Syntax
Create make(map[K]V)
Set m[key] = value
Get val := m[key]
Check val, ok := m[key]
Delete delete(m, key)
Length len(m)