我需要在Go中复制一个切片并阅读文档,我可以使用copy函数。
复制内置函数将元素从源切片复制到 目的地切片。 (作为一种特殊情况,它也会从a复制字节 字符串到一片字节。)源和目标可能重叠。 复制返回复制的元素数,这将是最小值 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]
您可以在playground上查看。那么为什么我不能复制片?
答案 0 :(得分:146)
内置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 Language Specification: Appending to and copying slices中记录了它:
复制的元素数量是
len(src)
和len(dst)
的最小值。
修改强>
最后,copy()
的文档已经更新,现在它包含了源和目标的最小长度将被复制的事实:
复制返回复制的元素数,即len(src)和len(dst)的最小。
答案 1 :(得分:13)
另一种简单的方法是使用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
<强>更新强>:
要不分配多余的内存,您可以事先设置所需的容量:
arr := []int{1, 2, 3}
tmp := make([]int, 0, len(arr))
tmp = append(tmp, arr...)
fmt.Println(len(tmp)) # 3
fmt.Println(cap(tmp)) # 3
答案 2 :(得分:11)
如果您的切片大小相同,it would work:
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]
来自&#34; Go Slices: usage and internals&#34;:
复制功能支持在不同长度的切片之间进行复制(它只会复制到较少数量的元素)
通常的例子是:
t := make([]byte, len(s), (cap(s)+1)*2)
copy(t, s)
s = t
答案 3 :(得分:8)
copy()运行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]
与allocation + copy()相比,对于超过1,000个元素,请使用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
答案 4 :(得分:2)
The Go Programming Language Specification
Appending to and copying slices
函数副本将切片元素从源src复制到 destination dst并返回复制的元素数。都 参数必须具有相同的元素类型T并且必须可分配给 一片[] T型。复制的元素数量是最小值 len(src)和len(dst)。作为一个特例,副本也接受一个 目标参数可赋值为带有source参数的type [] byte 字符串类型。此表单将字符串中的字节复制到 字节切片。
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]
答案 5 :(得分:0)
注意:这是@benlemasurier证明的错误解决方案
这是一种复制切片的方法。我来晚了一点,但是有一个比@Dave更快,更简单的答案。 This是从类似@Dave的代码生成的指令。 These是我的指令。如您所见,说明很少。它的作用就是复制切片的append(slice)
。这段代码:
package main
import "fmt"
func main() {
var foo = []int{1, 2, 3, 4, 5}
fmt.Println("foo:", foo)
var bar = append(foo)
fmt.Println("bar:", bar)
bar = append(bar, 6)
fmt.Println("foo after:", foo)
fmt.Println("bar after:", bar)
}
输出以下内容:
foo: [1 2 3 4 5]
bar: [1 2 3 4 5]
foo after: [1 2 3 4 5]
bar after: [1 2 3 4 5 6]
答案 6 :(得分:0)
克隆为切片的最佳方法是
sClone = append(s[:0:0], s...)
这种实现有两个优点:
如果s为nil,则确保结果sClone为nil,并且不为nil 如果 s 不为零。
即使 T 在 另一个包