В чем разница между длиной (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 (или другое значение, зависит от стратегии роста)

Ответ 18+ 🔞

А, слушай, вот эта хуйня про длину и ёмкость слайсов в Go — это вообще классика, блядь! Каждый новичок тут обосрётся, пока не поймёт, в чём разница. Сейчас разжую, как для дебила, но ты не обижайся, я сам через это проходил.

Представь себе, блядь, бутылку водки. Вот смотри:

  • Длина (Length) — это сколько водки в бутылке сейчас. То есть, сколько ты можешь сразу выпить, не бегая в магазин. Это len(s). Доступные стопки — от нулевой до len(s)-1.
  • Ёмкость (Capacity) — это полный объём бутылки, блядь! Сколько всего в неё может влезть, если доливать. Это 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 — а бутылка на пять стопок!

Теперь начинается магия append, блядь.

// Доливаем одну стопку. Длина стала 4, а ёмкость-то всё ещё 5!
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 (или около того, Go сам решает, хитрая жопа)

Вот и вся философия, блядь. Длина — это сколько есть. Ёмкость — это сколько может быть, пока не начнётся геморрой с поиском новой памяти. Запомни это, и будешь меньше ебаться с неожиданными аллокациями в своих циклах.