В чем разница между длиной (length) и ёмкостью (capacity) слайса в Go?

Ответ

Длина и ёмкость — это две фундаментальные характеристики слайса в Go, которые часто вызывают путаницу у новичков.


  • Длина (Length) — это количество элементов, которые слайс содержит на данный момент. Это значение возвращается функцией len(s). Вы можете получить доступ к элементам по индексу от 0 до len(s)-1.



  • Ёмкость (Capacity) — это количество элементов в базовом (скрытом) массиве, начиная с первого элемента слайса, которые могут быть использованы без необходимости нового выделения памяти. Это значение возвращается функцией cap(s). Ёмкость определяет, до какого размера слайс может вырасти с помощью append без реаллокации.


Всегда выполняется условие: 0 <= len(s) <= cap(s).

Пример создания и работы:

При создании слайса с помощью make можно указать и длину, и ёмкость.

// Создаем слайс с длиной 3 и ёмкостью 5
s := make([]int, 3, 5)

fmt.Println(s)        // Вывод: [0 0 0]
fmt.Println(len(s))   // Вывод: 3
fmt.Println(cap(s))   // Вывод: 5

В этом примере:

  1. Слайс s содержит 3 элемента (все инициализированы нулями).
  2. Мы можем добавить еще 5 - 3 = 2 элемента с помощью append без выделения новой памяти под базовый массив.
// Добавляем один элемент. Длина увеличивается, ёмкость та же.
s = append(s, 1)
fmt.Println(s)        // Вывод: [0 0 0 1]
fmt.Println(len(s))   // Вывод: 4
fmt.Println(cap(s))   // Вывод: 5

// Добавляем еще один элемент. Длина достигает ёмкости.
s = append(s, 2)
fmt.Println(s)        // Вывод: [0 0 0 1 2]
fmt.Println(len(s))   // Вывод: 5
fmt.Println(cap(s))   // Вывод: 5

// Добавляем еще один элемент. Происходит реаллокация.
// Go создает новый массив (обычно с удвоенной ёмкостью) и копирует туда старые элементы.
s = append(s, 3)
fmt.Println(s)        // Вывод: [0 0 0 1 2 3]
fmt.Println(len(s))   // Вывод: 6
fmt.Println(cap(s))   // Вывод: 10 (или другое значение, зависит от стратегии роста)