Golang: Копирование срезов
Срезы (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
), если ожидается независимость данных.
Задание
Реализуйте функцию IntsCopy(src []int, maxLen int) []int
, которая создает копию слайса src
с длиной maxLen
. Если maxLen
равен нулю или отрицательный, то функция возвращает пустой слайс []int{}
. Если maxLen
больше длины src
, то возвращается полная копия src
.
Полезное
Функция Clone() из модуля slices для копирования слайса
Встроенная функция copy() для копирования элементов из одного слайса в другой
Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект
Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи. В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества
Ваше упражнение проверяется по этим тестам
package solution
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestMap(t *testing.T) {
a := assert.New(t)
a.Equal([]int{}, IntsCopy([]int{}, 0))
a.Equal([]int{}, IntsCopy([]int{1, 2}, 0))
a.Equal([]int{}, IntsCopy([]int{1, 2}, -1))
a.Equal([]int{}, IntsCopy([]int{1, 2}, -5))
a.Equal([]int{1, 2}, IntsCopy([]int{1, 2, 3}, 2))
a.Equal([]int{1, 2, 3, 4}, IntsCopy([]int{1, 2, 3, 4}, 4))
a.Equal([]int{1, 2, 3, 4, 5}, IntsCopy([]int{1, 2, 3, 4, 5}, 10))
}
Решение учителя откроется через:
20:00
