The maps Package

Updated

September 13, 2026

The maps Package

The maps package provides generic functions over maps—everything you used to write with a for range.

Mental model

maps provides generic functions over maps. maps.Keys returns a slice of keys in unspecified order. maps.Values returns values. maps.Clone makes a shallow copy. maps.Copy merges src into dst (overwrites on conflict). maps.Equal compares two maps element-by-element. maps.DeleteFunc removes entries where the function returns true. Import is "maps".

Worked examples

Case 1: maps.Clone

Clone a map[string]int price menu, mutate the clone, and show the original is unchanged.

// clone.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    menu := map[string]int{
        "coffee": 250,
        "tea":    200,
    }

    clone := maps.Clone(menu)
    clone["coffee"] = 300
    clone["pastry"] = 450

    fmt.Printf("Original: %v\n", menu)
    fmt.Printf("Clone:    %v\n", clone)
}

Run:

go run clone.go

Output:

Original: map[coffee:250 tea:200]
Clone:    map[coffee:300 pastry:450 tea:200]

Case 2: maps.Keys and sorting

Get sorted keys for a seating chart using slices.Sort on the result for deterministic output.

// keys.go
package main

import (
    "fmt"
    "maps"
    "slices"
)

func main() {
    seats := map[string]string{
        "T1": "Alice",
        "T3": "Bob",
        "T2": "Charlie",
    }

    // maps.Keys returns an iterator; slices.Sorted collects and sorts in one step
    keys := slices.Sorted(maps.Keys(seats))

    fmt.Printf("Sorted desks: %v\n", keys)
}

Run:

go run keys.go

Output:

Sorted desks: [T1 T2 T3]

Case 3: maps.Copy

Merge two shift rosters map[string]string (name→window), showing a duplicate key is overwritten.

// copy.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    roster := map[string]string{
        "Alice": "Morning",
        "Bob":   "Evening",
    }

    updates := map[string]string{
        "Bob":     "Night",
        "Charlie": "Morning",
    }

    // src (updates) overwrites dst (roster)
    maps.Copy(roster, updates)

    fmt.Printf("Roster: %v\n", roster)
}

Run:

go run copy.go

Output:

Roster: map[Alice:Morning Bob:Night Charlie:Morning]

Case 4: maps.Equal

Compare two ticket priority maps, true then mutate one and false.

// equal.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    t1 := map[string]int{
        "T-100": 1,
        "T-101": 2,
    }
    t2 := map[string]int{
        "T-100": 1,
        "T-101": 2,
    }

    fmt.Printf("Equal initially? %v\n", maps.Equal(t1, t2))

    t2["T-102"] = 3
    fmt.Printf("Equal after mutation? %v\n", maps.Equal(t1, t2))
}

Run:

go run equal.go

Output:

Equal initially? true
Equal after mutation? false

Case 5: maps.DeleteFunc

Remove all menu items with price < 100 (cents).

// delete.go
package main

import (
    "fmt"
    "maps"
)

func main() {
    menu := map[string]int{
        "coffee": 250,
        "tea":    200,
        "water":  0,
        "mint":   50,
    }

    maps.DeleteFunc(menu, func(k string, v int) bool {
        return v < 100
    })

    fmt.Printf("Menu: %v\n", menu)
}

Run:

go run delete.go

Output:

Menu: map[coffee:250 tea:200]

The trap

Trap 1: maps.Clone is a shallow clone

maps.Clone creates a copy of the map, but it copies values as-is. If the map stores pointers or references to structs (map[string]*Ticket), both maps point to the exact same underlying heap objects. Mutating a field through the clone mutates the original!

Save as shallow_trap.go:

// shallow_trap.go
package main

import (
    "fmt"
    "maps"
)

type Ticket struct {
    ID     int
    Status string
}

func main() {
    original := map[string]*Ticket{
        "T-1": {ID: 101, Status: "open"},
    }

    clone := maps.Clone(original)
    // Mutating the pointed-to object changes both maps:
    clone["T-1"].Status = "closed"

    fmt.Println("original:", original["T-1"].Status)
    fmt.Println("clone:   ", clone["T-1"].Status)
}

Run:

go run shallow_trap.go

Output:

original: closed
clone:    closed

If you need a deep clone of pointer values, allocate a new struct for each key explicitly.

Trap 2: Assuming map iteration order is stable

maps.Keys returns an iterator over keys in randomized hash order. If you assume keys will always iterate in insertion or sorted order, tests and serialization logic will behave flakily across runs and Go compiler versions. Always use slices.Sorted(maps.Keys(m)) if order matters.

The boring rule

  • Use maps.Clone for simple value maps (map[string]int, map[string]string). For pointer values, clone structs explicitly.
  • Use slices.Sorted(maps.Keys(m)) to iterate keys deterministically.
  • Use maps.Copy(dst, src) to merge maps instead of manual loops.
  • Use maps.DeleteFunc for in-place conditional eviction (pruning expired cache entries, clearing completed orders).
  • Use maps.Equal for direct map comparisons.

Try this

  1. In keys.go, use slices.Sorted(maps.Values(seats)) to get a sorted list of guest names.
  2. In shallow_trap.go, fix the aliasing by constructing a new &Ticket{ID: t.ID, Status: t.Status} inside a copy loop. Confirm the original remains "open".
  3. In delete.go, change the predicate to keep only items whose names start with "c".