Go Cheatsheet

Slices and Maps

Use this Go reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Slices — Overview

A slice is a descriptor (pointer, length, capacity) over an underlying array. It is the primary dynamic collection in Go.

var s []int             // nil slice (len=0, cap=0)
s := []int{}            // empty (non-nil, len=0, cap=0)
s := []int{1, 2, 3}    // literal
s := make([]int, 5)     // len=5, cap=5, zeroed
s := make([]int, 3, 10) // len=3, cap=10

Slice Operations

s := []int{10, 20, 30, 40, 50}

len(s)       // 5 — number of elements
cap(s)       // capacity of underlying array

s[0]         // 10
s[1:3]       // [20 30]  — half-open [low:high)
s[:2]        // [10 20]  — from start
s[2:]        // [30 40 50] — to end
s[:]         // full copy of the slice header (same backing array)

append

s = append(s, 60)               // append single
s = append(s, 70, 80)           // append multiple
s = append(s, other...)         // append another slice

When the underlying array overflows, Go allocates a new one (typically 2× capacity). Always reassign: s = append(s, v).

copy

dst := make([]int, len(src))
n := copy(dst, src)   // copies min(len(dst), len(src)) elements; returns n copied

delete element at index i

// Preserves order — O(n)
s = append(s[:i], s[i+1:]...)

// Unordered (swap with last) — O(1)
s[i] = s[len(s)-1]
s = s[:len(s)-1]

insert at index i

s = append(s[:i+1], s[i:]...)
s[i] = value

Iterating Slices

for i, v := range s {
    fmt.Println(i, v)
}

for i := range s {  // index only
    s[i] *= 2
}

Multi-dimensional Slices

matrix := [][]int{
    {1, 2, 3},
    {4, 5, 6},
}
matrix[1][2]  // 6

// Allocate dynamically
rows, cols := 3, 4
m := make([][]int, rows)
for i := range m {
    m[i] = make([]int, cols)
}

Slice Gotchas

// Slices share the underlying array
a := []int{1, 2, 3, 4}
b := a[1:3]     // b = [2 3], shares a's array
b[0] = 99       // a is now [1 99 3 4]

// To get an independent copy:
c := append([]int(nil), a...)  // or copy into make()

// Full slice expression — limits capacity to prevent sharing
b = a[1:3:3]    // len=2, cap=2; append to b won't clobber a

// nil slice vs empty slice
var n []int      // nil;   len=0, n==nil → true
e := []int{}     // empty; len=0, e==nil → false
// Both are safe to range over, append to, pass to len/cap

Sorting Slices

import "sort"

ints := []int{3, 1, 4, 1, 5}
sort.Ints(ints)                           // ascending in-place
sort.Sort(sort.Reverse(sort.IntSlice(ints)))  // descending

strs := []string{"banana", "apple"}
sort.Strings(strs)

// Custom comparator
sort.Slice(ints, func(i, j int) bool {
    return ints[i] < ints[j]   // ascending
})
sort.SliceStable(ints, func(i, j int) bool { ... }) // stable sort

// Generic sort (Go 1.21+)
import "slices"
slices.Sort(ints)
slices.SortFunc(ints, func(a, b int) int { return cmp.Compare(a, b) })

slices Package (Go 1.21+)

import "slices"

slices.Contains(s, v)          // true if v in s
slices.Index(s, v)             // first index of v, -1 if absent
slices.Max(s)                  // maximum element
slices.Min(s)                  // minimum element
slices.Equal(a, b)             // element-wise equality
slices.Reverse(s)              // reverse in-place
slices.Compact(s)              // remove consecutive duplicates
slices.Delete(s, i, j)        // delete s[i:j]
slices.Insert(s, i, v...)     // insert at i
slices.Clone(s)                // shallow copy
slices.Grow(s, n)              // ensure cap >= len+n
slices.Clip(s)                 // trim excess capacity
slices.BinarySearch(s, v)     // (index, found) for sorted slice

Maps — Overview

A map is an unordered collection of key-value pairs. Keys must be comparable (==).

var m map[string]int         // nil map; read OK, write PANICS
m := map[string]int{}        // empty map (non-nil)
m := map[string]int{         // literal
    "alice": 25,
    "bob":   30,
}
m := make(map[string]int)           // empty
m := make(map[string]int, 100)      // with capacity hint

Map Operations

m := map[string]int{"a": 1}

// Read (zero value if absent)
v := m["a"]        // 1
v = m["z"]         // 0 (zero value)

// Comma-ok idiom
v, ok := m["a"]   // ok=true
v, ok  = m["z"]   // ok=false

// Write
m["b"] = 2

// Delete
delete(m, "a")

// Length
len(m)

// Iterate (order is random)
for k, v := range m {
    fmt.Println(k, v)
}
for k := range m { ... }   // keys only

Checking Existence

if v, ok := m[key]; ok {
    fmt.Println("found:", v)
} else {
    fmt.Println("missing")
}

maps Package (Go 1.21+)

import "maps"

maps.Keys(m)          // iterator over keys
maps.Values(m)        // iterator over values
maps.Clone(m)         // shallow copy
maps.Delete(m, func(k, v T) bool { ... })  // conditional delete
maps.Equal(m1, m2)    // key-value equality
maps.Copy(dst, src)   // merge src into dst

Common Map Patterns

Counting / frequency map

words := strings.Fields("the cat sat on the mat the")
freq := make(map[string]int)
for _, w := range words {
    freq[w]++
}

Grouping (map of slices)

byLen := make(map[int][]string)
for _, w := range words {
    byLen[len(w)] = append(byLen[len(w)], w)
}

Set (map to struct{})

seen := make(map[string]struct{})
seen["alice"] = struct{}{}
_, exists := seen["alice"]  // true

Default value with mutex (concurrent)

import "sync"

var mu sync.Mutex
m := make(map[string]int)

mu.Lock()
m["key"]++
mu.Unlock()

// Or use sync.Map for concurrent access without explicit locking
var sm sync.Map
sm.Store("key", 42)
v, ok := sm.Load("key")
sm.Delete("key")
sm.Range(func(k, v any) bool {
    fmt.Println(k, v)
    return true // continue iteration
})

Maps Are Reference Types

a := map[string]int{"x": 1}
b := a         // b references the same map
b["x"] = 99
fmt.Println(a["x"])  // 99

Nested Maps

graph := map[string]map[string]int{
    "a": {"b": 1, "c": 2},
    "b": {"c": 3},
}
graph["a"]["b"]  // 1

// Always initialize inner map before writing
if graph["d"] == nil {
    graph["d"] = make(map[string]int)
}
graph["d"]["e"] = 5

Map Gotchas

// Writing to a nil map panics
var m map[string]int
m["key"] = 1   // PANIC: assignment to entry in nil map

// Map is not safe for concurrent read+write
// Use sync.Mutex or sync.Map

// Map iteration order is randomized — never rely on it
// Keys can be any comparable type: int, string, struct (no slice/map/func)

// Deleting during range is safe in Go
for k := range m {
    if condition(k) {
        delete(m, k)
    }
}