copy函数复制切片时长度不对,是因为它只按min(len(dst), len(src))拷贝元素,不分配内存、不检查nil、不依赖cap;目标切片若为nil或len=0则返回0,需确保len(dst)≥len(src)才能全量复制。

copy函数复制切片时为什么长度不对?
Go 的 copy 函数不分配内存,只按「源长度」和「目标容量」取较小值来复制元素。常见现象是:目标切片明明声明了足够长,却只复制了 0 个或极少几个元素——本质是目标切片底层数组没预留空间,或者用 make([]T, 0) 初始化后忘了设置容量。
正确做法是确保目标切片有足够容量(capacity),而非仅看长度(length):
src := []int{1, 2, 3, 4, 5}
dst := make([]int, 0, len(src)) // ✅ 容量够,append 可用
dst = append(dst, src...) // 或用 copy:
dst = make([]int, len(src))
n := copy(dst, src) // n == 5
-
copy(dst, src)返回实际复制的元素个数,务必检查是否等于预期 - 若
dst是nil,copy安全返回 0,不会 panic - 不要对
dst用len(dst) == 0判断是否为空——它可能有容量但长度为 0
copy(dst, src) 参数顺序容易搞反吗?
会,而且搞反后果隐蔽:如果写成 copy(src, dst),多数时候复制 0 个元素(因为 src 长度小或为 nil),程序不报错但逻辑出错。这是 Go 中少数参数顺序不遵循 “dest, src” 惯例的内置函数(对比 os.Copy 是 dst, src)。
记住口诀:“copy 到哪,哪在前”——dst 在前,src 在后:
立即学习“go语言免费学习笔记(深入)”;
- ✅
copy(newSlice, oldSlice) - ❌
copy(oldSlice, newSlice)(除非你真想把 new 覆盖到 old 上) - 用 IDE 开启参数提示,或加注释:
// copy(dst, src)
复制子切片或重叠切片时要注意什么?
copy 支持重叠复制(比如同一底层数组内移动元素),但行为依赖方向:从左往右逐个赋值,因此 copy(s[i:], s[j:]) 在 i 时安全;若 <code>i > j 且重叠,会因覆盖导致数据丢失。
典型场景:删除切片中间元素后向前搬移:
s := []int{1, 2, 3, 4, 5}
// 删除索引 2(值为 3)
copy(s[2:], s[3:]) // ✅ 把 [4,5] 复制到 [2:] 位置
s = s[:len(s)-1] // 裁剪掉末尾冗余
- 重叠复制时,Go 保证「源未被覆盖部分」完整复制过去,但不保证中间状态
- 避免手动计算重叠边界,优先用
append(s[:i], s[i+1:]...)删除元素 - 复制子切片时,确认两边都基于有效底层数组,否则 panic:「slice bounds out of range」
为什么不能用 copy 复制 map 或 struct 字段?
copy 只接受切片类型参数,传入 map、struct、指针或数组会编译失败。常见误用是以为 copy(&dst, &src) 能深拷贝结构体——不行,Go 没有通用深拷贝函数。
- ❌
copy(&dstStruct, &srcStruct)→ 编译错误:cannot copy struct - ✅ 复制 struct 字段需逐字段赋值,或用
unsafe(不推荐)或第三方库如github.com/jinzhu/copier - ✅ 复制 map 元素需遍历:
for k, v := range srcMap { dstMap[k] = v } - 数组可直接赋值:
dstArray = srcArray(值拷贝),但切片是引用,必须用copy或append
真正容易被忽略的是:切片头(slice header)本身是值类型,a = b 只复制 header,不复制底层数组——所以别指望赋值能“复制数据”,该用 copy 还得用。


















