Все знают, что
append добавляет элемент в слайс. А вот что происходит, когда место в массиве кончилось, знают не всегда, и как раз тут прячется пара неожиданностей.У слайса есть
len и cap. Пока len меньше cap, append дописывает элемент прямо в тот же массив и возвращает слайс, который смотрит туда же. Никакого копирования, дёшево. Именно поэтому два слайса, делящие один массив, могут внезапно перетирать данные друг друга при append в один из них.Как только
cap исчерпан, рантайм выделяет новый массив побольше, копирует туда старые элементы и возвращает слайс уже на новую память. С этого момента старый и новый слайс не связаны, и запись в один не видна в другом. Отсюда правило, которое многих спасало от багов. Всегда присваивайте результат обратно.
s = append(s, x)
Точный коэффициент это деталь реализации, которая менялась от версии к версии, поэтому закладываться на конкретное число не стоит. Грубый ориентир такой. Маленькие слайсы растут примерно вдвое, большие прибавляют около четверти за раз, а переход между режимами сглажен в районе нескольких сотен элементов. Смысл в том, чтобы амортизировать стоимость и не копировать массив на каждом добавлении.
Если вы заранее знаете примерный размер, выделяйте вместимость сразу.
s := make([]int, 0, n)
for i := 0; i < n; i++ {
s = append(s, f(i))
}
Так вы избегаете череды перевыделений и копирований, а заодно снимаете нагрузку со сборщика мусора. На горячих циклах это заметно.
📍 Навигация: Вакансии • Задачи • Собесы
#GoDeep




