Ответ
Функция append
добавляет один или несколько элементов в конец слайса и возвращает новый слайс. Её работа зависит от ёмкости (capacity
) исходного слайса.
Алгоритм работы:
Проверка ёмкости: Go проверяет, достаточно ли места в нижележащем массиве (underlying array) для добавления новых элементов. Это сравнивается
len(slice) + len(new_elements)
сcap(slice)
.Если ёмкости достаточно (
cap
>len
):- Новые элементы добавляются в существующий нижележащий массив сразу после последнего элемента.
- Функция возвращает новый заголовок слайса, который указывает на тот же массив, но имеет обновленную длину (
len
).
Если ёмкости недостаточно (
cap
==len
):- Go выделяет новый, больший массив.
- Стратегия роста: для небольших слайсов ёмкость обычно удваивается. Для слайсов размером более 1024 элементов рост замедляется до ~1.25x, чтобы избежать избыточного расхода памяти.
- Все элементы из старого массива копируются в новый.
- Новые элементы добавляются в конец нового массива.
- Функция возвращает заголовок слайса, указывающий на этот новый массив.
Важный нюанс: append
и нижележащий массив
Поскольку append
может изменять существующий массив, это может приводить к неожиданному поведению, если несколько слайсов ссылаются на один и тот же массив.
package main
import "fmt"
func main() {
// Создаем массив и два слайса, указывающих на него
sourceArray := [5]int{10, 20, 30, 40, 50}
slice1 := sourceArray[0:2] // {10, 20}, len=2, cap=5
slice2 := sourceArray[1:3] // {20, 30}, len=2, cap=4
fmt.Printf("До: slice1=%v, slice2=%v, array=%vn", slice1, slice2, sourceArray)
// append для slice1 имеет достаточно ёмкости в sourceArray
slice1 = append(slice1, 99)
// Так как slice1 изменил нижележащий массив, slice2 тоже "увидел" это изменение
fmt.Printf("После: slice1=%v, slice2=%v, array=%vn", slice1, slice2, sourceArray)
// Вывод:
// До: slice1=[10 20], slice2=[20 30], array=[10 20 30 40 50]
// После: slice1=[10 20 99], slice2=[20 99], array=[10 20 99 40 50]
}
Золотое правило: Всегда присваивайте результат append
обратно в переменную слайса, так как функция может вернуть как измененный старый, так и совершенно новый слайс.
slice = append(slice, element)