Как написать код в Go, чтобы базовый слайс не менялся при изменениях?
Что проверяют
Понимаете ли вы, что слайс это не массив, а заголовок из указателя, длины и ёмкости поверх общего массива. Следом обычно дают код с append к подслайсу и просят предсказать, что станет с исходными данными.
Как отвечать
Начните с причины. Присваивание b := a, передача в функцию и взятие подслайса a[1:3] копируют только заголовок, массив остаётся общим, и любая запись b[0] = x видна через a. Независимую копию дают:
copy:dst := make([]int, len(src)); copy(dst, src). Копируетсяmin(len(dst), len(src))элементов;slices.Clone(s): с Go 1.21 в стандартной библиотеке, по сути этоappend(s[:0:0], s...);append([]int(nil), s...): старая идиома. Для пустого входа вернётnil, что бывает важно при сериализации в JSON.
Отдельно разберите append. Если у подслайса хватает ёмкости, append пишет в тот же массив и затирает элементы исходного слайса за границей подслайса. Защита без копирования: полное выражение среза a[1:3:3]. Ёмкость ограничена длиной, поэтому первый же append выделит новый массив. От прямой записи по индексу это, правда, не спасает.
И назовите границу: все эти способы делают поверхностную копию. Если элементы это указатели, мапы, вложенные слайсы или структуры с такими полями, данные под ними останутся общими, и глубокую копию придётся писать руками.
Где спотыкаются
Пишут var dst []int; copy(dst, src) или make([]int, 0, len(src)) и удивляются пустому результату. У dst длина 0, а copy смотрит на длину, не на ёмкость.
Уверены, что append всегда создаёт новый массив. Функция, которая делает append к переданному слайсу, может незаметно испортить данные вызывающего кода, пока не упрётся в ёмкость.
Копируют [][]int через slices.Clone и считают копию независимой. Внешний слайс новый, а строки внутри те же самые.