Go 常见错误集锦 | 不正确的 slice 复制

151 阅读2分钟

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战

大家好,我是Go学堂的渔夫子。本文给大家介绍下在使用copy函数对切片进行操作时的一些容易犯的错误及如何避免。

在Go中,内建的copy函数是将元素从源变量拷贝到目标变量中。该函数虽然方便,但在Go项目中并不常用。本节我们介绍一个使用copy复制错误的例子。

在下面的例子中,我们创建了一个slice变量,并将它的元素拷贝到另外一个slice变量中。我们看下面的代码会输出什么呢?

src := []int{0, 1, 2}
var dst []int
copy(dst, src)

运行该代码,将会输出空[],而不是[0 1 2]。这是为什么呢?

因为在使用copy函数时,copy是将两个切片变量中最小长度的元素个数拷贝到目的切片变量中。 用个公式表示应该会更简单点:

拷贝到变量dst中的元素个数 = min(len(dst), len(src))

在该示例中也就是 0,因为dst的长度是0,src的长度是3。所以,copy只能拷贝0个元素。这就是为什么最终dst切片是空的原因。

如果想拷贝一个完整的切片怎么办呢?那就需要目标切片的长度必须要大于或等于源切片的长度:

src := []int{0, 1, 2}
dst := make([]int, len(src)) ①
copy(dst, src)
fmt.Println(dst)

① 创建一个给定长度的切片

因为dst被初始化成长度为3的切片,所以它会被复制3个元素。如果我们运行该段代码,则会输出[0 1 2]。

现在我们理解了copy的工作方式,接下来我们更进一步的了解copy。下面的例子中,我们使用了copy后目标切片会是源切片的一个子切片:

s := []int{0, 1, 2, 3, 4}
copy(s[3:5], s) ①
fmt.Println(s)

① 目标切片是子切片s[3:5]

用示意图表示如下: 

s[3:5]是2个长度的切片,所有copy(s[3:5], s)将拷贝min(2, 5)个元素: 2个元素;从索引3开始。这种使用方式非常适合移动切片元素的场景。

总之,从一个切片将元素拷贝到另一个切片是非常常见的场景。我们必须谨记copy函数只会将两个切片(源切片和目标切片)中最小长度的元素个数拷贝到目标切片中。