What are slices in Go, and how do they differ from arrays?
go-jun-004
Your answer
Answer as you would in a real interview — explain your thinking, not just the conclusion.
Model answer
An array in Go has a fixed length that is part of its type: [3]int and [4]int are different types. Arrays are value types — assigning or passing them copies the entire data. A slice is a lightweight descriptor with three fields: a pointer to an underlying array, a length, and a capacity. Slices are reference types in the sense that multiple slices can share the same backing array. append() returns a new slice header; if len exceeds cap, Go allocates a new, larger array (typically doubling). A common gotcha: slicing an existing slice with s[a:b] shares the backing array — mutations through one slice are visible via the other until a reallocation occurs. Use copy() to break the shared backing array.
Code example
package main
import "fmt"
func main() {
// Array — value type, fixed length
arr := [3]int{1, 2, 3}
arr2 := arr // full copy
arr2[0] = 99
fmt.Println(arr[0]) // 1 — unaffected
// Slice — three-word header: ptr, len, cap
s := []int{1, 2, 3} // len=3, cap=3
s = append(s, 4) // len=4, cap=6 (new backing array)
// Sharing a backing array
a := []int{1, 2, 3, 4, 5}
b := a[1:3] // b shares backing array
b[0] = 99
fmt.Println(a) // [1 99 3 4 5] — a is mutated!
// Break sharing with copy
c := make([]int, len(b))
copy(c, b)
c[0] = 0
fmt.Println(a) // unaffected
// Pre-allocate to avoid reallocs
big := make([]int, 0, 1000)
for i := range 1000 {
big = append(big, i)
}
}
Follow-up
Explain what happens to memory when you append past a slice's capacity in a tight loop. How do you pre-allocate to avoid repeated reallocations?