> Какие способы копирования слайса в Go существуют (Go)
Уровень: senior · Роль: backend · Категория: Технические вопросы
Компании: Ozon, Лига Цифровой Экономики
Стек: Go
> Пример ответа
Короткий ответ
Основные способы копирования слайса в Go: copy(dst, src) для копирования элементов, срез src[:] для создания нового слайса с общим базовым массивом, append([]T(nil), src...) для полного копирования с новым массивом, и slices.Clone(src) из стандартной библиотеки (Go 1.21+). Выбор зависит от того, нужна ли независимая копия данных или достаточно нового заголовка слайса с общим массивом.
Подробное объяснение
Слайс в Go - это структура из трёх полей: указатель на массив, длина и ёмкость. Копирование слайса может означать два разных действия:
-
Копирование заголовка слайса - создание новой переменной, которая ссылается на тот же базовый массив. Это происходит при простом присваивании
b := aили при срезеb := a[1:3]. Изменения элементов черезbбудут видны черезa, так как массив общий. -
Копирование данных - создание нового массива и копирование в него элементов. Это делается через
copy,appendилиslices.Clone.
Основные способы:
-
copy(dst, src)- стандартная функция, копирует элементы изsrcвdst. Копируетсяmin(len(dst), len(src))элементов. Важно:dstдолжен быть заранее выделен нужного размера, иначе часть данных потеряется. -
append([]T(nil), src...)- идиоматический способ создать полную независимую копию. Выделяет новый массив нужной ёмкости и копирует все элементы. Работает для любого типаT. -
slices.Clone(src)- добавлена в Go 1.21, делает то же самое, что иappend, но читабельнее и оптимизирована. -
Срез
src[:]- не копирует данные, только создаёт новый заголовок. Используется, когда нужно передать слайс в функцию, не меняя его, или когда общий массив допустим. -
append(src[:0:0], src...)- трюк для копирования с сохранением исходного слайса, но без изменения его ёмкости. Редко используется, обычно достаточноappend([]T(nil), src...).
Важно помнить: все способы копирования данных выполняют shallow copy - если элементы слайса являются указателями, ссылками или структурами с указателями, сами объекты не копируются.
На практике
Выбор способа зависит от контекста:
- Если нужно передать слайс в функцию и гарантировать, что она не изменит исходные данные - используйте
slices.Cloneилиappend. - Если нужно скопировать только часть элементов - используйте
copyс предварительно выделеннымdst. - Если нужен новый слайс с тем же массивом (например, для ограничения длины) - используйте срез
src[:n]. - Если копируете слайс байт в буфер -
copy- самый эффективный вариант. - Для копирования в рамках одной функции, где исходный слайс больше не нужен, можно использовать
appendбез выделения нового массива, если ёмкость позволяет.
Пример кода
GOpackage mainimport ("fmt""slices")func main() {src := []int{1, 2, 3, 4, 5}// 1. Простое присваивание - общий массивa := srca[0] = 100fmt.Println(src[0]) // 100 - изменения видны// 2. copy - нужно выделить dst заранееdst := make([]int, len(src))n := copy(dst, src)fmt.Println(n, dst) // 5 [1 2 3 4 5]// 3. append - полная копияb := append([]int(nil), src...)b[0] = 200fmt.Println(src[0]) // 100 - исходный не изменился// 4. slices.Clone (Go 1.21+)c := slices.Clone(src)c[1] = 300fmt.Println(src[1]) // 2 - исходный не изменился// 5. Срез - новый заголовок, общий массивd := src[1:3]d[0] = 400fmt.Println(src[1]) // 400 - изменения видны}
Как отвечать на собеседовании
Начните с разграничения двух понятий: копирование заголовка слайса и копирование данных. Покажите, что понимаете устройство слайса (указатель, длина, ёмкость). Затем перечислите основные способы с акцентом на copy и append, упомяните slices.Clone как современный вариант. Обязательно отметьте shallow copy и что элементы-указатели не копируются глубоко. Приведите пример, когда какой способ уместен. Если спросят про производительность - copy быстрее, так как не выделяет память, если dst уже выделен; append и slices.Clone выделяют новый массив.
Что проверяет интервьюер
Интервьюер проверяет:
- Понимание внутреннего устройства слайса (заголовок vs массив).
- Знание стандартной библиотеки и идиом Go.
- Умение различать поверхностное и глубокое копирование.
- Понимание trade-off между выделением памяти и общим массивом.
- Способность выбрать правильный инструмент под задачу.
Типичные ошибки
- Использование
copyбез предварительного выделенияdst- копируется меньше элементов или ничего. - Утверждение, что
b := aсоздаёт копию данных - на самом деле это копия заголовка. - Забывают, что
copyкопирует толькоmin(len(dst), len(src))элементов. - Путают
slices.Cloneсslices.Copy(последней не существует, есть толькоcopy). - Считают, что срез
src[:]копирует данные - это не так. - Не упоминают shallow copy для слайсов с указателями или структурами с ссылочными полями.
> Похожие задачи по backend
Как сделать так, чтобы изменения слайса в функции были видны в вызывающей функции
Являются ли мапы в Go потокобезопасными
Приходилось ли работать с базами данных?
Что такое сбалансированное дерево
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью