编程Go开发者

copy()在Go中如何复制切片?与切片长度和容量增长相关的特点、限制和意外效果是什么?当切片相互重叠并尝试覆盖复制时,会发生什么?

用 Hintsage AI 助手通过面试

回答

函数copy(dst, src []T) int将元素从src复制到dst

  • 返回复制的元素数量:min(len(dst), len(src))
  • 复制是按索引进行的:元素src[i]被复制到dst[i]
  • 复制的是内容(值),而不是指向对象的指针。

细节和限制:

  • 如果切片重叠(例如,一个是另一个的子数组),复制按如下方式进行:首先获取原始值的快照,然后进行复制(在重叠情况下没有正确性的保证)。
  • 如果dst的长度小于src,只会复制dst所允许的长度的数据。
  • 如果dst的容量大于长度,copy是否会扩展切片?——不会,仅len(dst)被视为目标。要进行扩展,请提前使用append。

示例:

a := []int{1,2,3,4,5} b := make([]int, 3) copy(b, a) // b: [1 2 3]

重叠:

x := []int{1,2,3,4} copy(x[1:], x[:3]) // [1 1 2 3]

陷阱问题

copy()能否用于增加切片的长度?如果传递一个容量更大但长度更小的目的切片,会发生什么?

答案:

  • copy()不会改变目标切片的长度——只会复制到len(dst)
  • 如果dst的容量大于长度,请先通过dst = dst[:newLen]扩展它,然后使用copy()

示例,常常不明显:

a := []int{1,2,3} b := make([]int, 0, 5) copy(b, a) // b将保持为空,因为len(b)==0 b = b[:len(a)] copy(b, a) // 现在b: [1,2,3]

由于不了解主题的细节而导致的真实错误示例


故事

在项目中将数据从一个切片复制到另一个切片,认为copy会自动扩展dst的长度到所需的长度。结果并没有发生,元素未被复制,导致API的响应中出现了零数据。错误是在比较切片的长度后发现的——问题在于dst的容量很大,但长度为0。


故事

一部分微服务处理重叠的切片,错误地认为copy总是能正常工作。结果,向前复制破坏了原始数据,导致在处理缓冲区时出现“隐形”的bug。解决方案是使用临时缓冲区(copy(tmp, src),然后copy(dst, tmp))。


故事

工程师优化了数组,使用copy在切片之间排序数据。期望copy会调整dst的长度。结果发现没有发生,导致出现恐慌和超出有效数据的情况——在复制前忘记正确地调整切片的长度。