Arrays and Slices

Overview

Arrays and slices are Go’s primary sequence types. Arrays are fixed-size, while slices are dynamic views into arrays.

Arrays

Declaration

var arr [5]int                    // Zero values: [0 0 0 0 0]
arr := [5]int{1, 2, 3, 4, 5}     // Literal
arr := [...]int{1, 2, 3}          // Size inferred: [3]int

Properties

  • Fixed size (part of type): [5]int[6]int
  • Value semantics: copying creates independent copy
  • Zero value: array of zero values
a := [3]int{1, 2, 3}
b := a        // Copy!
b[0] = 99
fmt.Println(a)  // [1 2 3] (unchanged)

Slices

Creation

var s []int                      // nil slice
s := []int{1, 2, 3}             // Literal
s := make([]int, 5)             // Length 5, capacity 5
s := make([]int, 0, 10)         // Length 0, capacity 10

From Array

arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:4]  // [2 3 4] - shares memory with arr

Slice Internals

┌─────────┬─────────┬──────────┐
│ pointer │  len    │   cap    │
└────┬────┴─────────┴──────────┘
     │
     ▼
┌───┬───┬───┬───┬───┐
│ 1 │ 2 │ 3 │ 4 │ 5 │  (underlying array)
└───┴───┴───┴───┴───┘

Length and Capacity

s := make([]int, 3, 5)
len(s)  // 3 (elements accessible)
cap(s)  // 5 (space available)

Slice Operations

Append

s := []int{1, 2, 3}
s = append(s, 4)           // [1 2 3 4]
s = append(s, 5, 6, 7)     // [1 2 3 4 5 6 7]
s = append(s, other...)    // Append another slice

Slicing

s := []int{0, 1, 2, 3, 4, 5}
s[1:4]   // [1 2 3]
s[:3]    // [0 1 2]
s[3:]    // [3 4 5]
s[:]     // [0 1 2 3 4 5] (copy of slice header)

Copy

src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src)

The slices Package (Go 1.21+)

The standard library slices package provides generic utilities for common operations.

import "slices"

slices.Sort(nums)             // Sort in place
slices.Reverse(nums)          // Reverse in place
slices.Contains(nums, 42)     // Search
slices.Index(nums, 42)        // Find index
slices.Delete(nums, i, j)     // Remove range [i, j)
slices.Clone(nums)            // Shallow copy
slices.Equal(s1, s2)          // Compare

Modern Loop Pattern (Go 1.23+)

Using iterators with slices:

for i, v := range slices.All(nums) { /* ... */ }
for v := range slices.Values(nums) { /* ... */ }

nil vs Empty Slice

var nilSlice []int     // nil
emptySlice := []int{}  // not nil, but empty

nilSlice == nil        // true
emptySlice == nil      // false
len(nilSlice)          // 0
len(emptySlice)        // 0

Common Patterns

Remove Element

s = append(s[:i], s[i+1:]...)  // Remove element at index i

Insert Element

s = append(s[:i], append([]int{v}, s[i:]...)...)

Stack

stack = append(stack, v)             // Push
v, stack = stack[len(stack)-1], stack[:len(stack)-1]  // Pop

Summary

Feature Array Slice
Size Fixed Dynamic
Type [n]T []T
Zero value Array of zeros nil
Comparison == works Not comparable