Зарегистрируйтесь, чтобы продолжить обучение

Копирование срезов Основы Go

Срезы (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), если ожидается независимость данных.

Дополнительные материалы

  1. Функция Clone() из модуля slices для копирования слайса
  2. Встроенная функция copy() для копирования элементов из одного слайса в другой

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff