Подтвердить что ты не робот

Почему я не могу дублировать фрагмент с помощью "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]

Вы можете проверить это на игровой площадке. Так почему я не могу скопировать фрагмент?

4b9b3361

Ответ 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]