在 Go 语言里,slice 的浅拷贝与深拷贝分别指什么?它们之间有哪些区别?
考察说明
考察对 Go 语言 slice 底层结构及复制机制的理解,能否区分浅拷贝与深拷贝并说明实现方式。
回答思路
- 【回答框架 1】slice 的底层结构包含指向底层数组的指针、长度 len 和容量 cap。浅拷贝是指复制 slice 的这三个字段,得到的新 slice 与原 slice 共享同一个底层数组,因此通过任一 slice 修改元素都会影响另一个。
- 【回答框架 2】浅拷贝的典型方式是直接赋值或使用 s2 := s1。因为复制的是 slice 头,不复制底层数组,所以两个 slice 指向同一块内存区域。此时对新 slice 的元素进行写操作,原 slice 可见变化;但若进行 append 导致扩容,则会分配新数组,此后二者不再共享。
- 【回答框架 3】深拷贝是指复制底层数组,使新 slice 拥有独立的数组,修改互不影响。实现方式有使用 copy 函数(需预先分配目标切片长度)或手动循环复制元素。copy 返回复制的元素个数,且复制数量取决于 dst 和 src 中长度较小者。
- 【回答框架 4】选择深拷贝需考虑性能开销,因为需要额外分配内存并复制数据;而浅拷贝开销小,但需注意共享底层数组带来的副作用。在需要隔离数据以避免相互影响时,应使用深拷贝。
- 【关键点 1】浅拷贝复制 slice 头,底层数组共享;深拷贝复制底层数组,数据独立。
- 【关键点 2】直接赋值是浅拷贝,copy 函数或循环赋值可实现深拷贝。
- 【关键点 3】append 扩容后新 slice 与旧 slice 不再共享底层数组,但浅拷贝的元素修改仍相互可见。
- 【易错点 1】误以为浅拷贝后 append 一定会影响原 slice,实际上扩容后不再共享;未扩容时元素修改才互相影响。
- 【易错点 2】copy 函数复制的数量是 dst 和 src 中长度较小者,使用前需保证 dst 有足够长度,否则复制不完整。
- 【易错点 3】深拷贝会带来额外内存和性能开销,在性能敏感场景需权衡,避免无谓的大数组复制。