Какие свойства у слайса в Go
Что проверяют
Знаете ли вы, что слайс это не «динамический массив», а структура из трёх полей, и понимаете ли последствия: когда append переиспользует память, а когда копирует. Вопрос базовый, но следом почти всегда идёт задачка на алиасинг: что напечатает код, где два слайса смотрят в один массив.
Как отвечать
Начните со структуры. Слайс это заголовок из указателя на массив, длины len и ёмкости cap. Заголовок передаётся по значению: функция получает копию, поэтому запись s[0] = 1 видна снаружи, а результат append внутри функции снаружи не виден, если его не вернуть.
- append: если
capхватает, элемент пишется в тот же массив, и все слайсы поверх него видят изменение. Если не хватает, выделяется новый массив, и связь со старым рвётся; - рост ёмкости: не всегда вдвое. Примерно до 256 элементов ёмкость удваивается, дальше растёт плавнее, около 1.25 за шаг, и округляется до размерного класса аллокатора;
- срез:
s[2:5]делит память с исходным слайсом. Формаs[2:5:5]ограничивает ёмкость, и следующийappendгарантированно скопирует данные; - nil против пустого:
var s []intэто nil с нулевымиlenиcap, ноappendк нему работает.[]int{}не nil, хотя длина тоже 0. В JSON первый превращается вnull, второй в[]; - утечка: срез из трёх элементов большого слайса удерживает в памяти весь массив. Помогают
slices.Cloneиslices.Clip.
Упомяните стандартный пакет slices с Sort, Contains, Delete, Insert, Grow: руками такие операции уже не пишут.
Где спотыкаются
Говорят «слайс передаётся по ссылке». Передаётся копия заголовка, и путаница вылезает ровно на append внутри функции.
Не видят алиасинга: делают b := append(a[:2], x) и удивляются, что затёрли третий элемент a.
Считают удвоение ёмкости законом языка и строят на нём рассуждения о сложности. Это деталь реализации, которая уже менялась от версии к версии.