TGViewer
Библиотека Go-разработчика | Golang Библиотека Go-разработчика | Golang @goproglib · 24.1K subscribers
Post #7306 2.89K
📎 copy в Go простыми словами

Когда нужно перенести элементы из одного слайса в другой, рука тянется к циклу с индексом. Это рабочий вариант, но многословный и легко ошибиться с границами. Для этой задачи в языке есть встроенная функция copy.

➡️ Что делает copy

Сигнатура:
func copy(dst, src []Type) int


Функция берёт элементы из источника src и пишет их в dst. Возвращает число скопированных элементов. Это число всегда равно минимуму из длин двух слайсов:
src := []int{1, 2, 3, 4}
dst := make([]int, 2)
n := copy(dst, src)
fmt.Println(n, dst) // 2 [1 2]


Здесь у 'dst' длина 2, поэтому скопировались только первые два элемента, а остаток источника просто проигнорировался. Никакой ошибки или паники при этом нет.

➡️ Главное правило. Copy смотрит на длину, а не на capacity

Это та деталь, на которой спотыкаются чаще всего. copy пишет ровно в те ячейки, что уже есть в приёмнике, то есть ориентируется на его длину. Если создать слайс с нулевой длиной, но большим запасом capacity, копировать будет некуда:
dst := make([]int, 0, 10)
n := copy(dst, []int{1, 2, 3})
fmt.Println(n, dst) // 0 []


Длина нулевая, поэтому результат тоже ноль. Чтобы copy сработал, получатель должен иметь нужную длину заранее:
src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println(dst) // [1 2 3]


➡️ Как copy устроен внутри

Под капотом copy это не цикл с поэлементным присваиванием, а перемещение блока памяти, по поведению близкое к memmove из языка C. Из этого следует важное свойство. Источник и приёмник могут пересекаться по памяти, и результат всё равно будет корректным. Наивное копирование в цикле в такой ситуации затёрло бы данные, которые ещё не успело прочитать, а copy справляется правильно:
s := []int{1, 2, 3, 4, 5}
copy(s[1:], s[2:]) // сдвигаем хвост на одну позицию влево
fmt.Println(s) // [1 3 4 5 5]


Именно поэтому copy удобно использовать для сдвигов внутри одного слайса, например при удалении элемента:
i := 2
copy(s[i:], s[i+1:])
s = s[:len(s)-1]


➡️ Особый случай со строкой

Строку можно копировать прямо в []byte, хотя строка формально не слайс. Это разрешённое исключение в языке. Берётся, как обычно, минимум из длин:
dst := make([]byte, 5)
n := copy(dst, "hello world")
fmt.Println(n, string(dst)) // 5 hello


➡️ Copy копирует поверхностно

copy переносит сами значения элементов. Если элемент это указатель, слайс или мапа, в приёмник попадёт та же ссылка, а не отдельная копия вложенных данных. После копирования оба слайса будут указывать на одни и те же вложенные объекты, и изменение через один из них отразится на другом. Для глубокой копии вложенную структуру нужно клонировать отдельно.

➡️ Когда брать copy, а когда нет

copy нужен, когда вы пишете в уже выделенный буфер, копируете только часть данных или сдвигаете элементы внутри слайса. Если задача в том, чтобы получить полную копию слайса целиком, в стандартной библиотеке есть slices.Clone. Это короткая обёртка над тем же make плюс copy, и она читается яснее:
dst := slices.Clone(src)


copy берёт минимум из длин источника и приёмника, переносит элементы как блок памяти и возвращает число скопированных штук.

Держите в голове два момента:

• результат зависит от длины приёмника, а не от его capacity, поэтому буфер задают через make([]T, len(src)).

• копия поверхностная, вложенные ссылочные данные остаются общими. С этими двумя правилами copy становится простым и предсказуемым инструментом.

📍 Навигация: Вакансии • Задачи • Собесы

🐸 Библиотека Go-разработчика

#GoToProduction
  • 👍 12
  • ❤ 4
  • 😁 2
More from @goproglib
  1. Sep 26, 2026🔥 В Go 1.27 появился portable SIMD До этого SIMD-оптимизации в Go требовали архитектурног…
  2. Sep 25, 2026🤡🤡 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека Go-разработчика #GoGiggle
  3. Sep 25, 2026💡 Код работает. А data race уже есть В Go можно записать значение в одной горутине, прочи…
  4. Sep 23, 2026💥 TCP/IP: что происходит с данными в сети Когда Go-приложение отправляет данные по сети,…
  5. Sep 22, 2026🔴 Встроенные функции len, make, panic — встроенные функции Go, которые можно использовать…
  6. Sep 21, 2026🤩 Go с нуля: серия базовых шпаргалок Собрали путь от Hello, World! до goroutines, channel…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →