Go sort包无万能函数:基础切片用sort.Ints等,严格类型匹配;结构体等用sort.Slice但需注意闭包安全;稳定性需显式调用sort.SliceStable;数组须转切片排序。

Go 的 sort 包没有“万能排序函数”,选错方法会导致 panic、逻辑错乱或性能白耗——不是不会排,而是排得不对、不稳、不安全。
用 sort.Ints/sort.Strings 排基础切片,别碰 []int64 或字面量
这些函数专为 []int、[]string、[]float64 优化,语义清晰、零闭包开销、编译期强校验。但它们极其严格:
-
sort.Ints只认[]int,传[]int64会编译失败;想排[]int64?必须用sort.Slice - 传
nil切片会直接panic,调用前得自己判空:if data != nil { sort.Ints(data) } - 不能传字面量:
sort.Ints([]int{3,1,4})编译报错,因为切片字面量不可寻址 - 只支持升序;降序必须配
sort.Reverse或换sort.Slice
示例:sort.Strings(names) 安全又快;但 sort.Strings([]string{"a","b"}) ❌ 编译不过。
用 sort.Slice 排结构体、指针、多字段,但闭包里别捕获变量
这是 Go 1.8+ 后最常用的方式,灵活、无侵入、不用定义新类型。但它对写法很敏感:
立即学习“go语言免费学习笔记(深入)”;
在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface
- 比较函数签名是
func(i, j int) bool,返回true表示i应排在j前(即“i 在 j 左边”) - 必须用索引访问元素:
people[i].Age ✅;别写 <code>v.Age ❌(循环变量捕获陷阱) - 多字段排序用
if-else分层,别用&&连写:先比年龄,相等再比姓名,否则短路会跳过次级判断 - 字段必须可导出(首字母大写),否则闭包里读不到值;
[]*Person要先判nil,否则p[i].Name可能 panic
示例:sort.Slice(people, func(i, j int) bool { if people[i].Age != people[j].Age { return people[i].Age people[j].Name })
需要稳定排序?别信默认行为,必须显式用 sort.SliceStable 或 sort.Stable
Go 所有默认排序(包括 sort.Slice 和 sort.Sort)都不保证稳定性——相同键值的元素相对顺序可能被重排。这在分页、日志、带时间戳事件流中极易引发 bug:
-
sort.Slice底层是 pdqsort,不稳定;哪怕只是按分数排序,同分者原始提交顺序也会被打乱 - 要保持原始顺序?必须换
sort.SliceStable(students, func(i, j int) bool { return students[i].Score > students[j].Score }) -
sort.Stable配合自定义sort.Interface也行,但没必要——除非你已在多个地方复用同一排序类型 - 性能影响有限:百万级数据下慢 3%~8%,仅当“键重复 + 顺序敏感”时才值得切换
数组怎么排?先转切片,别试图绕过类型系统
Go 中 [5]int 是数组,不是切片;sort 全家桶只接受切片。常见误区是以为能直接排数组:
- 错误:
sort.Ints(myArray)❌ 编译失败,类型不匹配 - 正确:
sort.Ints(myArray[:])✅,myArray[:]返回共享底层数组的切片 - 注意:
myArray[:]不分配新内存,原数组内容会同步更新 - 如果数组是局部变量且后续不再用,这种转换完全安全;但若传参或跨 goroutine 使用,需确认并发安全
真正容易被忽略的,从来不是“怎么排”,而是“排完是否还符合业务预期”——比如同分者谁先显示、nil 指针有没有触发 panic、字段不可导出导致静默失效、还有那个你以为稳定的排序,其实早就悄悄打乱了顺序。

















