Rez Moss

Rez Moss

Personal Musings: A Blog for the Tech-Savvy and Curious Mind

Understanding Go's Slice Internals

Aug 2021

Go’s slices are a powerful and flexible data structure, but understanding their internals is crucial for efficient use. This article delves into the mechanics of slices and how they work under the hood.

Slice Structure

A slice is a descriptor of an array segment. It consists of: - A pointer to the array - The length of the segment - The capacity (the maximum length of the segment)

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

Creating Slices

When you create a slice, Go allocates an array and creates a slice structure pointing to it:

s := make([]int, 5, 10)
// Creates a slice with len 5, cap 10

Slice Operations

Appending

When appending to a slice, if there’s enough capacity, Go extends the length:

s := make([]int, 0, 5)
s = append(s, 1, 2, 3) // len 3, cap 5

If capacity is exceeded, Go allocates a new array with larger capacity:

s = append(s, 4, 5, 6) // len 6, cap 10 (new array allocated)

Slicing

Slicing creates a new slice structure pointing to the same array:

a := []int{1, 2, 3, 4, 5}
b := a[1:3] // b shares the same underlying array as a
  • Slices allow efficient passing of array segments without copying.
  • Be cautious with large slices to avoid keeping large arrays in memory.

Understanding slice internals helps in writing more efficient and bug-free Go code, especially when dealing with large data sets or performance-critical applications.