Проверяет понимание механизма роста динамического массива в Go и его влияние на производительность.
Слайс в Go — это структура, содержащая указатель на массив, длину и ёмкость. При вызове append, если длина меньше ёмкости, элемент просто добавляется в существующий массив. Если ёмкость исчерпана, Go выделяет новый массив большего размера, копирует туда все элементы и затем добавляет новый. Размер нового массива зависит от текущей ёмкости.
Для слайсов с ёмкостью менее 1024 элементов новая ёмкость обычно равна удвоенной старой. Для больших слайсов рост замедляется: новая ёмкость увеличивается примерно на 25% (точная формула зависит от версии Go и типа элемента). Это снижает количество выделений памяти для больших данных, но увеличивает среднее использование памяти.
package main
import "fmt"
func main() {
s := make([]int, 0, 2)
fmt.Println("cap:", cap(s)) // 2
s = append(s, 1, 2)
fmt.Println("cap:", cap(s)) // 2
s = append(s, 3)
fmt.Println("cap:", cap(s)) // 4 (удвоение)
s = append(s, 4, 5, 6)
fmt.Println("cap:", cap(s)) // 8 (удвоение)
}В этом примере видно, как ёмкость удваивается при каждом переполнении. Это стандартное поведение для небольших слайсов.
Понимание роста ёмкости важно для оптимизации: если заранее известно количество элементов, лучше использовать make с нужной ёмкостью, чтобы избежать лишних перераспределений. Это особенно критично в циклах с большим количеством append.
Итог: Рост ёмкости слайса — это компромисс между скоростью и памятью. Для большинства задач стандартное поведение достаточно, но при работе с большими объёмами данных стоит заранее выделять ёмкость, чтобы повысить производительность.