Что такое len и cap в слайсах Go и как они работают
Что проверяют
Понимаете ли вы устройство слайса и цену append. Для Go это входной вопрос: слайс это заголовок из указателя на массив, длины и ёмкости, и почти все ошибки с ним объясняются этими тремя полями.
Как отвечать
len это количество элементов, доступных по индексу прямо сейчас. cap это количество элементов от начала слайса до конца подлежащего массива, то есть сколько можно дописать, не выделяя новую память.
s := make([]int, 3, 8) // len 3, cap 8
s = append(s, 1) // len 4, cap 8, массив тот же
t := s[1:2] // len 1, cap 7Ключевое: ёмкость считается от начала слайса, а не от начала массива. Срез сдвигает начало и уменьшает cap ровно на сдвиг, а третий индекс (s[1:2:2]) ограничивает ёмкость явно.
Когда места не хватает, append выделяет новый массив, копирует элементы и возвращает новый заголовок, поэтому результат обязательно присваивают. Коэффициент роста это деталь реализации: короткие слайсы растут примерно вдвое, большие медленнее, опираться на конкретные числа нельзя. Если итоговый размер известен заранее, его задают через make с ёмкостью и снимают копирования вовсе.
Где спотыкаются
Ждут, что append не тронет исходный слайс. Пока ёмкости хватает, запись идёт в общий массив и видна всем слайсам на него, а после перевыделения связь рвётся. Поведение зависит от cap, то есть от предыстории, и именно поэтому такие места ловят гонками данных.
Режут слайс и получают удержание памяти. s[:1] уменьшает длину, но указатель на большой массив остаётся, и весь массив живёт дальше; отрезанные ссылочные элементы обнуляют или копируют нужное в новый слайс.
Путают make([]int, 10) и make([]int, 0, 10). Первый уже содержит десять нулей, и append допишет одиннадцатый элемент, а заготовка под десять элементов это вторая форма.