
Go 中 copy() 无法复制空切片,因其仅复制 min(len(src), len(dst)) 个元素;要成功复制,目标切片必须预先分配足够容量。
go 中 `copy()` 无法复制空切片,因其仅复制 `min(len(src), len(dst))` 个元素;要成功复制,目标切片必须预先分配足够容量。
在 Go 语言中,copy() 是一个内置函数,常被开发者误认为是“创建副本”的快捷方式。但它的实际行为更接近于内存块的底层拷贝操作:它将源切片(src)中的元素逐个复制到目标切片(dst)中,复制数量严格受限于两者长度的较小值——即 n = min(len(src), len(dst))。这意味着:若目标切片长度为 0(如 []int{} 或 make([]int, 0)),无论源切片多长,copy() 都不会写入任何元素。
例如,以下代码看似合理,实则无效:
arr := []int{1, 2, 3}
tmp := []int{} // len(tmp) == 0
n := copy(tmp, arr)
fmt.Println("copied:", n, "tmp:", tmp) // 输出: copied: 0 tmp: []运行结果中 n == 0,tmp 保持为空,正是因为 len(tmp) == 0,导致 min(3, 0) == 0。
✅ 正确做法是:为目标切片预分配与源切片等长(或至少足够长)的底层数组空间。最常用且语义清晰的方式是使用 make():
arr := []int{1, 2, 3}
tmp := make([]int, len(arr)) // 分配长度为 3 的新切片
copy(tmp, arr)
fmt.Println("tmp:", tmp) // [1 2 3]
fmt.Println("arr:", arr) // [1 2 3](原切片未被修改)⚠️ 注意事项:
- copy() 不改变目标切片的长度,只填充其已有长度范围内的元素。因此 make([]int, len(arr)) 创建的是长度和容量均为 len(arr) 的切片,完全满足需求;
- 若只需浅拷贝且后续可能追加元素,可使用 make([]int, 0, len(arr)) 配合 append(但此时 copy() 仍需目标有非零长度才能生效);
- copy() 支持重叠拷贝(如 copy(arr[1:], arr)),适用于原地移位操作,但复制切片时通常应避免重叠以保证逻辑清晰;
- copy() 返回实际复制的元素数量,建议在关键路径中检查该返回值以增强健壮性(尤其当源/目标长度动态变化时)。
? 总结:copy() 不是“构造副本”的构造函数,而是“填充已有空间”的工具。牢记口诀:先分配,再复制(make → copy)。这一模式也适用于字符串转 []byte、多维切片子区域拷贝等场景,是 Go 内存安全与显式控制哲学的典型体现。










