Ответ
Встроенная функция append
всегда возвращает новый срез, но он может указывать как на тот же базовый массив (underlying array), что и исходный срез, так и на совершенно новый.
Поведение зависит от capacity
(емкости) исходного среза:
Если
capacity
достаточна: Новый элемент добавляется в существующий базовый массив. Возвращается новый срез, который указывает на тот же массив, но имеет увеличенную длину (len
).- Важный побочный эффект: Так как базовый массив общий, его изменение будет видно через оба среза (старый и новый), что может привести к неожиданному поведению.
Если
capacity
недостаточна: Go выделяет новый, больший массив, копирует в него все элементы из старого, добавляет новый элемент и возвращает срез, указывающий на этот новый массив.
Пример:
// Сценарий 1: Емкости хватает
original := make([]int, 2, 5) // len=2, cap=5
original[0], original[1] = 10, 20
fmt.Printf("Original: len=%d, cap=%d, %vn", len(original), cap(original), original)
appended := append(original, 30)
fmt.Printf("Appended: len=%d, cap=%d, %vn", len(appended), cap(appended), appended)
// Изменим элемент в новом срезе
appended[0] = 99
// Изменение отразится и в исходном, т.к. массив один и тот же!
fmt.Printf("Original after change: %vn", original) // Вывод: [99 20]
// Сценарий 2: Емкости не хватает, создается новый массив
slice := []int{1, 2, 3} // len=3, cap=3
newSlice := append(slice, 4)
newSlice[0] = 100
fmt.Println("slice:", slice) // Вывод: [1 2 3] (не изменился)
fmt.Println("newSlice:", newSlice) // Вывод: [100 2 3 4]
Ключевой вывод и лучшая практика: Всегда присваивайте результат append
переменной, чаще всего той же самой: mySlice = append(mySlice, newValue)
. Это гарантирует, что вы работаете с корректным (возможно, новым) срезом.