Irbisa · Cheatsheet
Slices, Maps & Strings
Slice headers, append aliasing, map internals, runes and strings.Builder
What is the difference between an array and a slice in Go, and what does a slice header contain?
arr := [4]int{1, 2, 3, 4}cp := arr // array: full copycp[0] = 99fmt.Println(arr[0]) // 1 s := arr[1:3] // slice over arr: len 2, cap 3…What is the difference between a nil slice and an empty slice, and what can you do with a nil slice?
What is the difference between
make([]T, n)andmake([]T, 0, n), and what goes wrong when youappendto the first one?in := []string{"a", "b", "c"} // wrong: three zero Rows first, then the three real onesout := make([]Row, len(in))for _, v := range in { out = append(out, Row{Key: v})…How do you make an independent copy of a slice, and why does
copyintomake([]T, 0, n)copy nothing?a := []int{1, 2, 3} b := a // header copy: same arrayb[0] = 99fmt.Println(a[0]) // 99…What does this loop print, and how do you change the elements of a slice inside a
rangeloop?type Item struct { Name string Count int} items := []Item{{"a", 1}, {"b", 2}}for _, it := range items { it.Count++}fmt.Println(items)Why does
len("Дмитрий")return 14, and how do you count, index and iterate the characters of a Go string?name := "Дмитрий" fmt.Println(len(name)) // 14 (bytes)fmt.Println(utf8.RuneCountInString(name)) // 7 (runes)fmt.Println(name[0]) // 208 (one byte, not "Д")…How do you check whether a key exists in a map, and what happens when you write to a map you never initialised?
orders := map[string]int{"ada": 0} fmt.Println(orders["grace"]) // 0 (missing key, no panic)n, ok := orders["ada"]fmt.Println(n, ok) // 0 true (a stored zero)…Why is the iteration order of a Go map random, and how do you get a stable order?
m := map[string]int{"b": 2, "a": 1, "c": 3} for k, v := range m { // the order differs between runs fmt.Println(k, v)}…How do you sort a slice of structs by one field, and by two fields?
type User struct { Name string Age int} users := []User{{"Bob", 30}, {"Alice", 30}, {"Eve", 25}}…Is a slice passed to a function by value or by reference? What does this program print?
func add(s []int) { s[0] = 100 s = append(s, 4) s[1] = 200} func main() { a := make([]int, 3, 10) add(a) fmt.Println(a, len(a), a[:4])}How does
appendgrow a slice, and when does it allocate a new array?var sink []int var s []intprev := -1for i := 0; i < 2000; i++ { s = append(s, i)…Two slices are appended from the same base slice. What does this code print, and why?
base := make([]int, 2, 3) // [0 0], one free slotx := append(base, 1)y := append(base, 2)fmt.Println(x, y) z := append(x, 3) // x is already fullz[0] = 7fmt.Println(x[0], z[0])What does the three-index slice expression
s[low:high:max]do, and when do you need it?buf := []int{1, 2, 3, 4, 5} head := buf[:2] // len 2, cap 5head = append(head, 99) // overwrites buf[2]fmt.Println(buf) // [1 2 99 4 5]…Why is building a string with
s += partin a loop slow, and when do you usestrings.Builder,strings.Joinorbytes.Buffer?// wrong: each += copies everything built so fars := ""for _, line := range lines { s += line + "\n"}…Is it safe to delete from or add to a map while ranging over it?
Why does
m["a"].Count++not compile whenmis amap[string]Item, and how do you update a struct stored in a map?type Item struct{ Count int } m := map[string]Item{"a": {Count: 1}}m["a"].Count++ // wrong: cannot assign to struct field m["a"].Count in map it := m["a"] // right: copy out, change, store back…How is a Go map implemented, and what changed when Go 1.24 switched to Swiss tables?
Is a Go map safe for concurrent use? What happens on concurrent writes, and how do you protect a shared map?
type Cache struct { mu sync.RWMutex m map[string]Entry} func NewCache() *Cache {…What do the
slicesandmapspackages replace, and whichslicesfunctions change the slice you pass in?ids := []int{3, 1, 3, 2}fmt.Println(slices.Contains(ids, 2), slices.Index(ids, 3)) // true 0 slices.Sort(ids) // in place: [1 2 3 3]ids = slices.Compact(ids) // [1 2 3]ids = slices.Insert(ids, 1, 10) // [1 10 2 3]…Find the bug: after
removeExpired, some expired sessions are still in the slice.type Session struct { ID string ExpiresAt time.Time} // removeExpired drops every session that has expired.func removeExpired(sessions []Session, now time.Time) []Session { for i := 0; i < len(sessions); i++ { if sessions[i].ExpiresAt.Before(now) { sessions = append(sessions[:i], sessions[i+1:]...) } } return sessions}Does
s = s[:5]free the rest of a large slice? How can a small subslice keep a big array in memory?var keep []byte keep = body[:64] // wrong: pins the whole 4 MB bodykeep = bytes.Clone(body[:64]) // right: copy what you keep clear(s[n:]) // slice of pointers: drop the stale references…Removing an element with
s = append(s[:i], s[i+1:]...)works, so how can it leak memory, and what doesslices.Deletedo differently?// the old last pointer stays in the slot past len(sessions)sessions = append(sessions[:i], sessions[i+1:]...) // Go 1.22+: the same shift, the vacated slot zeroedsessions = slices.Delete(sessions, i, i+1)…Can several goroutines use the same slice or
[]bytebuffer, and how do you do it safely?func process(buf []byte, workers int) { size := (len(buf) + workers - 1) / workers var wg sync.WaitGroup for lo := 0; lo < len(buf); lo += size { hi := min(lo+size, len(buf)) wg.Add(1)…Find the bug:
Renamereturns without error, butListstill shows the old name for some users.type Registry struct { users []User // keeps insertion order for List byID map[int]*User // fast lookup by ID} func (r *Registry) Add(u User) { r.users = append(r.users, u) r.byID[u.ID] = &r.users[len(r.users)-1]} func (r *Registry) Rename(id int, name string) { r.byID[id].Name = name} func (r *Registry) List() []User { return r.users }