Arrays vs slices in Go: the differences, with examples
An array is a fixed box of values. A slice is a window onto one. You will use slices 99% of the time.
- List the differences between an array and a slice in Go.
- Predict when changing one slice changes another.
- Say when an array is the better choice.
An array has a fixed length that is part of its type: [3]int. A slice is a small header (pointer, length, capacity) that looks at part of an array: []int. Here is the difference at a glance.
| Array `[3]int` | Slice `[]int` | |
|---|---|---|
| Length | Fixed, part of the type | Can grow with append |
| Passed to a function | Whole array is copied | Only the header is copied; data is shared |
| Zero value | All elements zero | nil (length 0) |
Compare with == | Yes | No (only with nil) |
| Use as a map key | Yes | No |
len / cap | Both equal the fixed length | Can differ |
| How often you use it | Rarely | All the time |
What is the difference between an array and a slice in Go?
An array’s length is fixed and part of its type, and assigning or passing it copies every element. A slice is a view over an array that can grow, and copying a slice shares the same elements. Full details are in Arrays and slices.
package mainimport "fmt"func setFirstArray(a [3]int) { a[0] = 99 } // gets a copyfunc setFirstSlice(s []int) { s[0] = 99 } // shares the datafunc main() { arr := [3]int{1, 2, 3} sl := []int{1, 2, 3} setFirstArray(arr) setFirstSlice(sl) fmt.Println("array after call:", arr) // unchanged fmt.Println("slice after call:", sl) // changed b := arr // copies the array b[1] = 0 fmt.Println("arr == [3]int{1, 2, 3}:", arr == [3]int{1, 2, 3}) t := sl // copies only the header t[1] = 0 fmt.Println("sl after t[1] = 0:", sl)}Is a slice passed by reference in Go?
No. Go passes everything by value, slices too. But a slice value is a header holding a pointer, so the copy points at the same elements. Changing s[i] is seen by the caller; append that grows the slice is not, unless you return it.
What are len and cap of a slice?
len is how many elements you can index now. cap is how many fit in the backing array before append must allocate a new, bigger one. When that happens the slice moves to new memory and stops sharing with the old one.
package mainimport "fmt"func main() { a := []int{1, 2, 3, 4} b := a[:2] fmt.Println(len(b), cap(b)) // 2 4: room left in a's array b = append(b, 9) // fits, so it writes into a's array fmt.Println("a:", a) c := a[:2:2] // capacity capped at 2 c = append(c, 7) // no room: copies to a new array fmt.Println("a:", a, "c:", c)}When should you use an array instead of a slice?
When the size is fixed and meaningful, and you want copying or comparison: a SHA-256 hash ([32]byte), an RGB colour ([3]uint8), or a map key like [2]int for grid coordinates. Everywhere else, use a slice.
- Array: fixed length, part of the type, copied on assign and pass.
- Slice: pointer + len + cap over an array; copies share elements.
- Arrays can be compared and used as map keys; slices cannot.
appendmay move a slice to a new array; always writes = append(s, x).- Use
s[a:b:b]to stop append overwriting the original.
- 1What does
fmt.Println([2]int{1, 2} == [2]int{1, 2})print? What about the same with slices? - 2Write a function that appends to a slice and make the caller see the new element.
- 3Use
map[[2]int]boolto mark visited cells (0,0) and (1,2) in a grid, then print whether (1,2) was visited.