Go语言中合并两个切片的惯用方法与规范写法
Go中合并切片的惯用写法(适配golangci-lint检查)
在Go里合并两个切片生成新切片时,很多人会第一时间写出这样的代码:
fruits := []string{"banana", "strawberry"} vegetables := []string{"potato", "carrot"} food := append(fruits, vegetables...)
但这种写法会触发golangci-lint中gocritic: appendAssign规则的报错,提示“append result not assigned to the same slice”。
为什么会报错?
这个lint规则的核心是避免开发者忽略切片的底层数组特性:如果原切片fruits的剩余容量足够容纳vegetables的元素,append会直接在fruits的底层数组上追加元素,此时food和fruits会共享同一段底层数组,后续修改food可能意外篡改fruits的内容。直接赋值给新变量的写法,容易让开发者忽略这种共享风险。
最惯用的两种写法
1. 先赋值原切片再追加(适配lint规则)
这就是示例中能通过检查的写法,明确表达food是基于fruits扩展而来,让开发者更清晰地意识到切片的引用特性:
fruits := []string{"banana", "strawberry"} vegetables := []string{"potato", "carrot"} food := fruits food = append(food, vegetables...)
2. 预分配容量的高效写法
如果提前知道两个切片的长度,推荐预分配目标切片的容量,这样可以避免内存重新分配,提升性能,这也是Go中处理切片的惯用优化手段:
fruits := []string{"banana", "strawberry"} vegetables := []string{"potato", "carrot"} // 预分配足够容纳两个切片所有元素的容量 food := make([]string, 0, len(fruits)+len(vegetables)) food = append(food, fruits...) food = append(food, vegetables...)
这种写法不仅能通过lint检查,还能避免底层数组共享的问题(因为新切片是重新分配的内存),同时性能更优。
两种写法的区别
- 第一种写法可能和原切片共享底层数组,适合不需要隔离原切片内容、追求代码简洁的场景;
- 第二种写法完全独立于原切片,适合需要避免原切片被意外修改、追求性能的场景。
内容的提问来源于stack exchange,提问作者jonhadfield
相关产品推荐
相关产品推荐

