Почему я не могу дублировать фрагмент с помощью "copy()"?
Мне нужно сделать копию фрагмента в Go и читать документы, в моем распоряжении есть функция копирования.
Встроенная функция копирования копирует элементы из исходного слайса в целевой слайс. (В особом случае он также будет копировать байты из строки в секцию байтов.) Источник и назначение могут перекрываться. Copy возвращает количество скопированных элементов, которое будет минимальным из len (src) и len (dst).
Но, когда я делаю:
arr := []int{1, 2, 3}
tmp := []int{}
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)
Мой tmp
пуст, как это было раньше (я даже пытался использовать arr, tmp
):
[]
[1 2 3]
Вы можете проверить это на игровой площадке. Так почему я не могу скопировать фрагмент?
Ответы
Ответ 1
Встроенный copy(dst, src)
копирует элементы min(len(dst), len(src))
.
Итак, если ваш dst
пуст (len(dst) == 0
), ничего не будет скопировано.
Попробуйте tmp := make([]int, len(arr))
(Go Playground):
arr := []int{1, 2, 3}
tmp := make([]int, len(arr))
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)
Выход (как ожидалось):
[1 2 3]
[1 2 3]
К сожалению, это не описано в пакете builtin
, но оно задокументировано в Спецификация языка Go: добавление и копирование фрагментов:
Количество скопированных элементов - это минимум len(src)
и len(dst)
.
Edit:
Наконец, документация copy()
была обновлена, и теперь она содержит тот факт, что минимальная длина источника и адресата будет скопирована:
Копия возвращает количество скопированных элементов, которое будет минимум для len (src) и len (dst).
Ответ 2
Еще один простой способ сделать это - использовать append
который выделит срез в процессе.
arr := []int{1, 2, 3}
tmp := append([]int(nil), arr...) // Notice the ... splat
fmt.Println(tmp)
fmt.Println(arr)
Выход (как и ожидалось):
[1 2 3]
[1 2 3]
Поэтому сокращение для копирования массива arr
будет append([]int(nil), arr...)
https://play.golang.org/p/sr_4ofs5GW
Ответ 3
Если ваши фрагменты имели одинаковый размер, он будет работать:
arr := []int{1, 2, 3}
tmp := []int{0, 0, 0}
i := copy(tmp, arr)
fmt.Println(i)
fmt.Println(tmp)
fmt.Println(arr)
Давал бы:
3
[1 2 3]
[1 2 3]
От "Перейти к фрагментам: использование и внутренние параметры":
Функция копирования поддерживает копирование между фрагментами различной длины (будет копироваться только до меньшего количества элементов)
Обычный пример:
t := make([]byte, len(s), (cap(s)+1)*2)
copy(t, s)
s = t
Ответ 4
Копия() выполняется для наименьшей длины dst и src, поэтому вы должны инициализировать dst до нужной длины.
A := []int{1, 2, 3}
B := make([]int, 3)
copy(B, A)
C := make([]int, 2)
copy(C, A)
fmt.Println(A, B, C)
Вывод:
[1 2 3] [1 2 3] [1 2]
Вы можете инициализировать и копировать все элементы в одной строке, используя append(), в нулевой фрагмент.
x := append([]T{}, []...)
Пример:
A := []int{1, 2, 3}
B := append([]int{}, A...)
C := append([]int{}, A[:2]...)
fmt.Println(A, B, C)
Вывод:
[1 2 3] [1 2 3] [1 2]
Сравнивая с alloc + copy(), для более 1000 элементов используйте append. Фактически ниже 1000 разницей можно пренебречь, сделайте это для эмпирического правила, если у вас много кусочков.
BenchmarkCopy1-4 50000000 27.0 ns/op
BenchmarkCopy10-4 30000000 53.3 ns/op
BenchmarkCopy100-4 10000000 229 ns/op
BenchmarkCopy1000-4 1000000 1942 ns/op
BenchmarkCopy10000-4 100000 18009 ns/op
BenchmarkCopy100000-4 10000 220113 ns/op
BenchmarkCopy1000000-4 1000 2028157 ns/op
BenchmarkCopy10000000-4 100 15323924 ns/op
BenchmarkCopy100000000-4 1 1200488116 ns/op
BenchmarkAppend1-4 50000000 34.2 ns/op
BenchmarkAppend10-4 20000000 60.0 ns/op
BenchmarkAppend100-4 5000000 240 ns/op
BenchmarkAppend1000-4 1000000 1832 ns/op
BenchmarkAppend10000-4 100000 13378 ns/op
BenchmarkAppend100000-4 10000 142397 ns/op
BenchmarkAppend1000000-4 2000 1053891 ns/op
BenchmarkAppend10000000-4 200 9500541 ns/op
BenchmarkAppend100000000-4 20 176361861 ns/op
Ответ 5
Спецификация языка программирования Go
Добавление и копирование фрагментов
Функция копирования копирует элементы среза из источника src в destination dst и возвращает количество копируемых элементов. И то и другое аргументы должны иметь одинаковый тип типа T и должны быть отнесены к кусочек типа [] T. Количество скопированных элементов - это минимум len (src) и len (dst). В качестве специального случая копия также принимает параметр назначения, назначаемый типу [] байт с аргументом источника строкового типа. Эта форма копирует байты из строки в байтовый срез.
copy(dst, src []T) int
copy(dst []byte, src string) int
tmp
достаточно места для arr
. Например,
package main
import "fmt"
func main() {
arr := []int{1, 2, 3}
tmp := make([]int, len(arr))
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)
}
Вывод:
[1 2 3]
[1 2 3]