Проверяет понимание внутреннего устройства срезов в Go и влияния append на общий базовый массив.
Срез — это дескриптор, который содержит три поля: указатель на первый элемент базового массива, длину (len) и ёмкость (cap). Базовый массив — это обычный массив фиксированного размера, на который ссылается срез. Когда вы создаёте срез от массива или другого среза, все они могут разделять один и тот же базовый массив.
Функция append добавляет элементы в конец среза. Если текущая ёмкость среза позволяет (len < cap), append записывает новые элементы в базовый массив сразу после последнего элемента и увеличивает длину среза. В этом случае все срезы, которые ссылаются на тот же базовый массив и имеют достаточную длину, увидят изменения. Если же ёмкость исчерпана (len == cap), append выделяет новый массив большего размера (обычно в два раза больше), копирует туда старые элементы и добавляет новые. После этого срез указывает на новый массив, и изменения больше не затрагивают старый базовый массив.
arr := [5]int{1, 2, 3, 4, 5}
s1 := arr[:3] // len=3, cap=5
s2 := arr[2:] // len=3, cap=3
s1 = append(s1, 10) // ёмкости достаточно, запись в arr[3]
fmt.Println(arr) // [1 2 3 10 5]
fmt.Println(s2) // [3 10 5] — изменение видно
s2 = append(s2, 20) // ёмкости не хватает, создаётся новый массив
fmt.Println(arr) // [1 2 3 10 5] — старый массив не изменился
fmt.Println(s2) // [3 10 5 20] — новый срезИзменение одного среза влияет на другой только в том случае, если оба среза используют один и тот же базовый массив, и запись происходит в пределах длины этого массива. Если append вызывает перераспределение (создание нового массива), то связь разрывается, и дальнейшие изменения не затрагивают другие срезы. Также важно помнить, что запись в элемент среза (например, s[0] = 100) всегда изменяет базовый массив, поэтому все срезы, ссылающиеся на него, увидят это изменение.
Понимание работы append с общим базовым массивом критично для избежания неожиданных побочных эффектов в Go. Если вы хотите гарантировать независимость срезов, используйте функцию copy или создавайте новый срез с достаточной ёмкостью. Это особенно важно при работе с большими структурами данных и конкурентным доступом, где неявное изменение данных может привести к трудноуловимым ошибкам.