Что такое емкость слайса и зачем она нужна
Что проверяют
Понимаете ли вы устройство слайса и последствия: когда происходит реаллокация, кто с кем делит массив и почему после append данные вызывающего могут измениться. Вопрос базовый, поэтому ценится точность формулировок.
Как отвечать
Слайс это заголовок из трёх полей: указатель на массив, длина и ёмкость. Ёмкость это сколько элементов помещается от начала слайса до конца массива. Пока длина меньше ёмкости, append пишет в свободный хвост без аллокаций. Когда места нет, рантайм выделяет новый массив, копирует туда содержимое и возвращает новый заголовок. Поэтому «ёмкость слайса выросла» неточно: выросла ёмкость нового значения, старый заголовок остался прежним.
s := make([]int, 0, 1000) // тысяча append без единой реаллокации
t := s[:5:5] // третье число это верхняя граница ёмкостиЗачем нужна. Первое: известен размер, задаём ёмкость в make и экономим копирования, каждый рост это аллокация плюс копирование плюс работа для сборщика. Второе важнее: ёмкость решает, куда попадёт append. Если два слайса смотрят в один массив и у первого есть запас, append по нему перезапишет элементы второго. Трёхиндексный срез обрезает ёмкость и делает такой append безопасным.
Где спотыкаются
Говорят, что ёмкость всегда растёт вдвое. Коэффициент зависит от текущего размера и от версии рантайма, для крупных слайсов рост меньше, а итог округляется до класса размеров аллокатора. Правильный ответ: рост амортизированно постоянный, конкретное число надо смотреть, а не предсказывать.
Не видят алиасинга. Функция получила слайс, сделала append, и вызывающий либо увидел чужую запись в своих данных, либо не увидел свою, если внутри произошла реаллокация. Это и есть причина возвращать слайс из функции, а не полагаться на изменение на месте.
Держат короткий слайс от большого массива и удивляются, что память не отдаётся. Ссылка на первый элемент удерживает весь массив целиком, и после разбора большого буфера нужна копия нужного куска, а не срез от него.