Go 中使用 copy() 复制切片的正确方法详解

3次阅读

Go 中使用 copy() 复制切片的正确方法详解

copy() 函数不会自动分配目标切片内存,它仅复制 min(len(src), len(dst)) 个元素;若目标切片为空(长度为 0),则无任何元素被复制——必须预先分配足够容量的目标切片。

`copy()` 函数不会自动分配目标切片内存,它仅复制 `min(len(src), len(dst))` 个元素;若目标切片为空(长度为 0),则无任何元素被复制——必须预先分配足够容量的目标切片。

go 中,copy(dst, src) 是标准库提供的内置函数,常被初学者误认为是“创建副本”的万能工具。但实际上,它不负责内存分配,而是一个纯粹的内存拷贝操作:将源切片 src 的前 n 个元素复制到目标切片 dst 的起始位置,其中 n = min(len(src), len(dst))。

这意味着:
✅ 若 dst 已有足够长度(如 make([]int, len(src))),则完整复制成功;
❌ 若 dst 长度为 0(例如 []int{} 或 make([]int, 0)),则 n = 0,复制零个元素,dst 保持不变。

✅ 正确用法:预分配目标切片

arr := []int{1, 2, 3} tmp := make([]int, len(arr)) // 关键:按需分配长度(非容量!) copy(tmp, arr) fmt.Println(tmp) // 输出: [1 2 3] fmt.Println(arr) // 输出: [1 2 3]

? 注意:make([]T, len) 分配的是长度(Length,而非仅容量(capacity)。copy() 依赖的是 len(dst),因此必须确保目标切片具有足够长度——容量更大不影响复制,但长度不足会导致截断。

⚠️ 常见错误与误区

  • ❌ tmp := []int{} → 长度为 0,copy 无效果;
  • ❌ tmp := make([]int, 0) → 同样长度为 0;
  • ❌ tmp := make([]int, 0, len(arr)) → 容量充足但长度为 0,仍无法复制;
  • ✅ tmp := make([]int, len(arr)) → 长度匹配,安全可靠;
  • ✅ tmp := append([]int(nil), arr…) → 利用 append 实现语义化深拷贝(推荐用于简洁场景)。

? 进阶技巧:灵活复制与子切片处理

若只需复制部分元素,可结合切片表达式:

arr := []string{"a", "b", "c", "d", "e"} partial := make([]string, 2) copy(partial, arr[1:3]) // 复制 "b", "c" fmt.Println(partial) // [b c]

此外,对于引用类型(如 []*int),copy() 仅复制指针值,不深拷贝底层数据——这是浅拷贝行为,需按需手动处理。

✅ 总结

要点 说明
核心规则 copy(dst, src) 复制 min(len(dst), len(src)) 个元素,长度决定上限
必要前提 dst 必须预先通过 make 或字面量初始化,且 len(dst) > 0
最佳实践 使用 make([]T, len(src)) 分配目标切片,清晰、高效、无歧义
替代方案 append(make([]T, 0, len(src)), src…) 可避免显式 copy,语义更直观

理解 copy() 的“零分配、纯搬运”本质,是写出健壮 Go 切片操作代码的关键一步。

text=ZqhQzanResources