copy 函数在目标切片为 nil 或 len=0 时返回 0 而不 panic,因其实现仅取 min(len(dst), len(src)) 作为拷贝数;它不检查 nil、不初始化底层数组,也不关心 cap,仅依赖 len。

目标切片是 nil 时 copy 不 panic,但返回 0
Go 的 copy 函数不会检查 dst 是否为 nil,也不会主动初始化它。它只做一件事:从 src[0] 开始,把元素一个一个往 dst 的底层数组里写——前提是 dst 有底层数组、有长度、且长度 > 0。如果 dst == nil,它的长度是 0,copy 直接返回 0,不报错也不写入。
-
dst := []int(nil)或未声明直接传参(如copy(dst, src)中dst未赋值),都属于 nil 切片 - nil 切片的
len(dst) == 0,所以min(len(dst), len(src)) == 0,复制数为 0 - 程序看似“没出错”,但目标位置仍是空的——这不是 bug,是设计使然;Go 把初始化责任留给调用方
目标切片长度不够,只拷贝前 N 个元素
copy 的实际拷贝数量永远取 len(dst) 和 len(src) 的较小值。哪怕 dst 容量足够,只要长度不够,多余元素就被丢弃。
- 例如
dst := make([]int, 2),src := []int{1,2,3,4},copy(dst, src)只复制前两个元素,返回 2 - 这和 Java 的
Arrays.copyOf行为类似,但 Go 不抛异常,容易被忽略 - 若你期望“全量复制”,必须确保
len(dst) >= len(src);常用写法是dst := make([]T, len(src))
用 make 分配时,len 和 cap 搞混会导致静默失败
很多人写 dst := make([]int, 0, len(src)),以为“容量够就能 copy”,结果发现 dst 还是空的。因为 copy 看的是 len(dst),不是 cap(dst)。
-
make([]int, 0, 10)创建的是长度为 0、容量为 10 的切片,copy仍返回 0 - 正确做法:要填充数据,就得让长度 ≥ 拷贝数,比如
make([]int, len(src))或make([]int, 0, len(src)); dst = dst[:len(src)] - 后者更省内存(避免初始化零值),但多了一步切片重设,容易漏
最常被忽略的点是:nil 和 len=0 的切片行为一致(都导致 copy 返回 0),但它们在其他场景下语义不同——比如 append 对 nil 切片合法,对 len=0 的非-nil 切片也合法,唯独 copy 对两者一视同仁:不初始化,就不干活。

















