sort.Slice是Go 1.8+最常用自定义排序方式,适用于结构体、多字段、降序等场景;需注意切片可寻址、字段导出、多条件用if-else、基本类型优先用专用函数、nil需过滤、稳定排序用SliceStable、复用逻辑才实现Interface、所有排序均原地修改。

用 sort.Slice 实现任意切片的自定义排序
这是 Go 1.8+ 后最常用、最直接的方式,适合绝大多数场景——结构体、指针切片、多字段条件、降序、按长度/时间/嵌套字段排序等,全靠一个闭包搞定。
- 比较函数签名是
func(i, j int) bool,返回true表示第i个元素应排在第j个前面(即“i 在 j 前”) - 切片必须可寻址:不能对字面量直接调用,比如
sort.Slice([]int{1,2}, ...)会编译报错;得先赋值给变量再传 - 访问字段时确保可导出(首字母大写),否则闭包里读不到值
- 多条件排序用
if-else分层判断,别堆&&,否则相等分支逻辑容易写反
例如按年龄升序、同龄按姓名降序:
sort.Slice(people, func(i, j int) bool {
if people[i].Age != people[j].Age {
return people[i].Age < people[j].Age
}
return people[i].Name > people[j].Name
})
对基本类型切片优先用 sort.Ints、sort.Strings 等内置函数
它们专为 []int、[]string、[]float64 优化,比 sort.Slice 略快,且不会因闭包捕获变量引发隐式 bug。
-
sort.Ints和sort.Strings只支持升序;要降序,得用sort.Slice或sort.Sort(sort.Reverse(sort.IntSlice(s))) - 这些函数不接受自定义逻辑:想按字符串长度排
[]string?必须换sort.Slice - 传入含
nil的[]*string会 panic,得自己提前过滤或判空
需要稳定排序时,必须用 sort.SliceStable
当排序键有重复(如多人分数相同),又希望保持原始输入中它们的相对顺序(比如提交先后),普通 sort.Slice 不保证这点,它底层用的是快排变种,不稳定。
立即学习“go语言免费学习笔记(深入)”;
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
-
sort.SliceStable接口和sort.Slice完全一致,只是算法换成了稳定版本(如归并) - 性能略低,但仅在“键重复 + 顺序敏感”时才值得切换
- 常见于分页列表、日志聚合、带时间戳的事件流排序
例如分数相同的学生,按原始录入顺序保留:
sort.SliceStable(students, func(i, j int) bool {
return students[i].Score > students[j].Score
})
复用排序逻辑?实现 sort.Interface 是唯一选择
当你在多个地方反复按同一规则排序(比如“按价格降序”“按创建时间升序”),或者想把排序能力“绑定”到某个类型上,就该封装成新类型并实现 Len、Less、Swap 三个方法。
- 注意:必须定义新类型(如
type ByPrice []Product),不能直接在原类型上实现,否则会循环引用 -
Less方法是核心,写法和sort.Slice闭包一样,但作用域更明确 - 如果只是临时一用,硬写接口反而啰嗦;只有真正复用 ≥2 次,才值得这么做
最容易忽略的一点:所有排序都是原地修改,无论用哪种方式,原切片内容都会变——没做拷贝的话,上游数据就没了。









