【Golang】slice append 和copy对比
正确
1 | func reconstructQueue(people [][]int) [][]int { |
错误
1 | unc reconstructQueue(people [][]int) [][]int { |
两个 reconstructQueue
函数的主要区别在于 插入元素的方式,而第二个版本能通过是因为它正确处理了 切片的动态扩容和元素移动
关键问题分析
1. 第一个版本的问题(Slice 操作)
1 | result = append(result, info) // 先追加元素(长度+1) |
问题原因:
append(result[:pos+1], result[pos:]...)
会导致数据错乱
当pos
不是最后一个位置时,result[pos:]
会包含刚刚追加的info
(因为上一步append(result, info)
已经增加了长度),导致切片拼接时重复复制元素,最终结果错误。
2. 第二个版本的正确性(copy 操作)
1 | result = append(result, info) // 先追加元素(长度+1) |
为什么正确:
copy
直接覆盖内存,不会因append
的嵌套调用引发数据错乱。- 逻辑清晰:先扩展切片,再移动元素,最后插入新值。
修复第一个版本的方法
如果仍想用 Slice 操作,需避免提前追加元素,改为直接插入:
1 | func reconstructQueue(people [][]int) [][]int { |
关键修改:
- 使用
append([][]int{info}, result[pos:]...)
一次性完成插入,避免提前扩展切片。
两种方式的对比
操作方式 | 代码示例 | 优点 | 缺点 |
---|---|---|---|
copy | copy(result[pos+1:], result[pos:]) | 内存操作直接,不易出错 | 代码稍显冗长 |
Slice 拼接 | append(result[:pos], append([][]int{info}, result[pos:]...)...) | 代码简洁 | 嵌套 append 可读性略低 |
为什么第二个版本更鲁棒?
copy
是底层内存复制
不会受切片共享或嵌套append
的影响,适合需要精确控制内存的场景。append
的嵌套可能导致临时切片
在复杂逻辑中容易引入错误(如你的第一个版本)。
总结
- 推荐使用
copy
的版本:逻辑清晰,适合大多数场景。 - 如果追求代码简洁,可以用修复后的 Slice 拼接,但需注意
append
的副作用。
关键教训:在操作切片时,**避免在同一个逻辑块中混合多次
append
**,除非你能确保切片长度的变化不会影响后续操作。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Lei Qi's Blog!
评论