- Копирование с помощью slices.Clone()
- Частичное копирование с помощью copy()
- Копирование с помощью append()
- Почему простого присваивания недостаточно
- Пример: безопасное клонирование перед модификацией
- Рекомендации
Срезы (slices
) в Go передаются по значению, но содержат указатель на данные, поэтому простое присваивание приводит к совместному использованию одной и той же области памяти. Изменения в одном срезе могут повлиять на другой:
a := []int{1, 2, 3}
b := a
b[0] = 100
// изменился и a
fmt.Println(a) // => [100 2 3]
fmt.Println(b) // => [100 2 3]
Чтобы избежать таких побочных эффектов, нужно явно копировать содержимое среза.
Копирование с помощью slices.Clone()
Стандартный пакет slices
предлагает удобную функцию Clone()
, которая создаёт новый срез с тем же содержимым, не изменяя оригинал:
import "slices"
original := []int{1, 2, 3}
clone := slices.Clone(original)
clone[0] = 100
fmt.Println(original) // => [1 2 3]
fmt.Println(clone) // => [100 2 3]
Функция Clone
всегда создаёт новый срез с собственной памятью.
Частичное копирование с помощью copy()
Если нужно скопировать данные из одного среза в другой, используйте функцию copy()
:
src := []int{1, 2, 3}
dst := make([]int, 2)
copy(dst, src)
fmt.Println(dst) // => [1 2]
Копируется min(len(src), len(dst))
элементов.
Копирование с помощью append()
Ещё один способ безопасно скопировать срез — использовать append
:
src := []int{1, 2, 3}
dst := append([]int(nil), src...) // или: append(make([]int, 0, len(src)), src...)
Создаётся новый срез, и содержимое копируется в него.
Почему простого присваивания недостаточно
Присваивание среза копирует только структуру (указатель, длину и ёмкость), но не сам массив. В результате оба среза указывают на один и тот же участок памяти:
a := []string{"hello", "world"}
b := a
b[0] = "hi"
// слайс 'a' изменился!
fmt.Println(a) // => [hi world]
fmt.Println(b) // => [hi world]
Пример: безопасное клонирование перед модификацией
import "slices"
func transform(data []int) []int {
clone := slices.Clone(data)
for i := range clone {
clone[i] *= 2
}
return clone
}
func main() {
values := []int{1, 2, 3}
newValues := transform(values)
fmt.Println(values) // => [1 2 3]
fmt.Println(newValues) // => [2 4 6]
}
Рекомендации
- Функция
slices.Clone()
удобна для создания независимой копии среза. - Используйте
copy()
илиappend()
для ручного клонирования или переноса элементов. - Избегайте присваивания (
b := a
), если ожидается независимость данных.