copy() 复制值而非引用,目标与源切片底层数组分离、互不影响;它不分配新数组,仅逐元素拷贝,且要求目标切片已预分配足够空间。

copy() 复制的是值,不是引用
调用 copy() 后,目标切片和源切片的数据不再共享底层数组 —— 修改其中任一个,另一个完全不受影响。这是它和直接赋值(如 s2 = s1)最根本的区别。
常见错误现象:以为 copy(dst, src) 后改 dst 会影响 src,或反过来;其实两者彻底独立,除非你手动再让它们重叠(比如用同一底层数组的不同区间做 src 和 dst)。
-
copy()不会分配新底层数组,它只逐元素拷贝已有数据;目标切片必须已分配空间且足够大 - 如果
len(src) > len(dst),只复制前len(dst)个元素,返回值就是这个数 - 如果
len(src) ,只覆盖前 <code>len(src)个位置,dst剩余部分保持原值
直接赋值是浅拷贝,共享底层数组
写 s2 := s1 或传参给函数时,s2 和 s1 指向同一底层数组的同一段内存 —— 它们是同一个“窗口”,只是名字不同。改任意一个的元素,另一个立刻可见变化。
容易踩的坑:在函数里接收 slice 参数后直接修改其元素,结果意外改变了调用方的原始数据;或者误以为 s2 == nil 就代表没数据,其实只要 s1 非空,s2 就有内容(哪怕 len(s2)==0)。
- 切片变量本身是轻量结构(指针 + len + cap),赋值开销极小
- 判断是否为空必须用
len(s) == 0,不能用s == nil,因为s2 := s1后s2永远不为nil(除非s1是nil) - 扩容操作(如
append)可能触发底层数组重建,此时新旧切片才真正分离
什么时候该用 copy(),而不是直接赋值
核心判断标准:你需要一份**独立、可自由修改**的数据副本,且不希望副作用波及原始数据。
典型使用场景:
- 从网络或文件读取一批数据,先存进缓存切片,再异步处理 —— 必须
copy(),否则读后续数据会覆盖正在处理的旧数据 - 函数需要返回一个“当前快照”,但内部仍要继续修改原始切片 —— 返回前
copy()出新切片 - 实现类似
Clone()的方法,对外暴露不可变视图
性能提示:copy() 是 memmove 级别优化的,比手写 for 循环快;但若只是临时读取、不修改,直接赋值更省资源。
copy() 的边界行为和常见 panic
copy() 本身不会 panic,但它依赖目标切片已分配空间。最常触发 panic 的其实是后续操作 —— 比如复制后对 dst 做 append,却忘了 dst 的 cap 可能很小,导致底层数组被意外复用。
- 目标切片为
nil:copy()返回 0,不 panic,但什么也没做 - 源切片为
nil:同样返回 0,安全 - 目标切片长度为 0 但容量非 0(如
make([]int, 0, 10)):可以正常 copy,数据写入底层数组起始位置 - 复制重叠区间(如
copy(s[1:], s)):Go 允许,且按从左到右顺序安全处理,等价于 memmove
最容易被忽略的一点:copy 后的切片长度不变,你得自己用 s = s[:n] 调整长度,否则多出来的旧数据还在那里,可能引发逻辑错误。











