Go Maps

Creating Maps

make, literal, and nil maps
// Create with make
m := make(map[string]int)
m["alice"] = 42
m["bob"]   = 17

// Literal
scores := map[string]int{
    "alice": 42,
    "bob":   17,
}

// nil map — reads work, writes panic
var empty map[string]int
fmt.Println(empty["x"])  // 0 (zero value, no panic)
// empty["x"] = 1        // PANIC: assignment to entry in nil map

Always make or use a literal before writing to a map. Reading from a nil or missing key returns the zero value of the value type.

The Comma-Ok Idiom

Distinguish "key absent" from "value is zero"
m := map[string]int{"alice": 0, "bob": 17}

val, ok := m["alice"]
fmt.Println(val, ok)  // 0 true

val, ok = m["carol"]
fmt.Println(val, ok)  // 0 false

if v, ok := m["bob"]; ok {
    fmt.Printf("bob: %d\n", v)
}

Without the second return value, you cannot tell whether a key exists with value 0 or is missing entirely.

Delete & Iterate

delete removes a key; range iterates
m := map[string]int{"a": 1, "b": 2, "c": 3}

delete(m, "b")  // no-op if key missing

// Iteration order is random
for k, v := range m {
    fmt.Printf("%s: %d\n", k, v)
}

// Sorted iteration — extract keys first
keys := make([]string, 0, len(m))
for k := range m {
    keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
    fmt.Printf("%s: %d\n", k, m[k])
}

Map iteration order is deliberately randomized by the Go runtime. If you need deterministic output, sort the keys.

Patterns

Word frequency counter
func wordFreq(text string) map[string]int {
    freq := make(map[string]int)
    for _, word := range strings.Fields(text) {
        freq[word]++  // zero value of int is 0
    }
    return freq
}
Set using map[T]struct{}
type Set map[string]struct{}

func (s Set) Add(item string)    { s[item] = struct{}{} }
func (s Set) Has(item string) bool { _, ok := s[item]; return ok }
func (s Set) Remove(item string) { delete(s, item) }

seen := make(Set)
seen.Add("10.50.1.1")
if seen.Has("10.50.1.1") {
    fmt.Println("already seen")
}

struct{} consumes zero bytes. map[T]struct{} is the idiomatic Go set — more memory-efficient than map[T]bool.

Group by — map of slices
type Host struct {
    Name string
    VLAN int
}

func groupByVLAN(hosts []Host) map[int][]Host {
    groups := make(map[int][]Host)
    for _, h := range hosts {
        groups[h.VLAN] = append(groups[h.VLAN], h)
    }
    return groups
}

append on a nil slice works correctly, so there is no need to check whether the key exists before appending.