关于go:为什么我不能在Golang中复制带有`copy()`的切片?

Why can not I duplicate a slice with `copy()` in Golang?

我需要在Go中制作一个切片的副本,并且阅读文档,我可以使用一个复制功能。

The copy built-in function copies elements from a source slice into a
destination slice. (As a special case, it also will copy bytes from a
string to a slice of bytes.) The source and destination may overlap.
Copy returns the number of elements copied, which will be the minimum
of len(src) and len(dst).

但当我这样做的时候:

1
2
3
4
5
arr := []int{1, 2, 3}
tmp := []int{}
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)

我的tmp和以前一样是空的(我甚至试着用arr, tmp):

1
2
[]
[1 2 3]

你可以在游乐场查看。为什么我不能复制一个切片?


内置的copy(dst, src)复制min(len(dst), len(src))元素。

因此,如果您的dst为空(len(dst) == 0),则不会复制任何内容。

试试tmp := make([]int, len(arr))(去操场):

1
2
3
4
5
arr := []int{1, 2, 3}
tmp := make([]int, len(arr))
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)

输出(如预期):

1
2
[1 2 3]
[1 2 3]

不幸的是,在builtin包中没有记录这一点,但在Go语言规范中有记录:附加和复制片:

The number of elements copied is the minimum of len(src) and len(dst).

编辑:

最后,更新了copy()的文档,现在它包含了这样一个事实:源和目标的最小长度将被复制:

Copy returns the number of elements copied, which will be the minimum of len(src) and len(dst).


另一种简单的方法是使用append,它将在进程中分配切片。

1
2
3
4
arr := []int{1, 2, 3}
tmp := append([]int(nil), arr...)  // Notice the ... splat
fmt.Println(tmp)
fmt.Println(arr)

输出(如预期):

1
2
[1 2 3]
[1 2 3]

所以复制数组arr的简写就是append([]int(nil), arr...)

https://play.golang.org/p/sr ofs5gw


如果您的切片大小相同,它将工作:

1
2
3
4
5
6
arr := []int{1, 2, 3}
tmp := []int{0, 0, 0}
i := copy(tmp, arr)
fmt.Println(i)
fmt.Println(tmp)
fmt.Println(arr)

将给予:

1
2
3
3
[1 2 3]
[1 2 3]

从"Go Slices:用法和内部结构"开始:

The copy function supports copying between slices of different lengths (it will copy only up to the smaller number of elements)

通常的例子是:

1
2
3
t := make([]byte, len(s), (cap(s)+1)*2)
copy(t, s)
s = t

copy()运行的DST和SRC长度最小,因此必须将DST初始化为所需的长度。

1
2
3
4
5
6
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
[1 2 3] [1 2 3] [1 2]

可以使用append()初始化一行中的所有元素并将其复制到nil切片。

1
x := append([]T{}, []...)

例子:

1
2
3
4
A := []int{1, 2, 3}
B := append([]int{}, A...)
C := append([]int{}, A[:2]...)
fmt.Println(A, B, C)

输出:

1
[1 2 3] [1 2 3] [1 2]

与allocation+copy()相比,对于大于1000个元素,请使用append。实际上,低于1000的差异可能会被忽略,使它成为一个经验法则,除非你有许多切片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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


The Go Programming Language Specification

Appending to and copying slices

The function copy copies slice elements from a source src to a
destination dst and returns the number of elements copied. Both
arguments must have identical element type T and must be assignable to
a slice of type []T. The number of elements copied is the minimum of
len(src) and len(dst). As a special case, copy also accepts a
destination argument assignable to type []byte with a source argument
of a string type. This form copies the bytes from the string into the
byte slice.

1
2
copy(dst, src []T) int
copy(dst []byte, src string) int

tmp需要足够的空间供arr使用。例如,

1
2
3
4
5
6
7
8
9
10
11
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
[1 2 3]
[1 2 3]