译文 Go 常见错误集锦之不正确的 slice 复制

yudotyang · 2021年10月11日 · 48 次阅读

本文是对《100 Go Mistackes:How to Avoid Them》一书的翻译。因翻译水平有限,难免存在翻译准确性问题,敬请谅解。更多内容请关注公众号--Go 学堂

大家好,我是 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 函数只会将两个切片(源切片和目标切片)中最小长度的元素个数拷贝到目标切片中。

更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册