用 sort.Slice 就对了,它自 Go 1.8 起是结构体切片排序的事实标准,无需定义新类型或实现三个方法,只需传切片和比较闭包;注意字段必须导出、切片需可寻址、指针和浮点字段需额外判空与 NaN 处理。

用 sort.Slice 就对了,别绕弯写 sort.Interface,除非你真要复用同一套排序逻辑十几次。
为什么 sort.Slice 是默认答案
Go 1.8 起它就是结构体切片排序的事实标准:不用定义新类型、不写三个方法、闭包里直接写字段比较。它只认两样东西——一个切片变量,和一个 func(i, j int) bool 函数。
- 字段必须导出(首字母大写),否则闭包里访问不到,编译报
cannot refer to unexported field - 切片不能是字面量,比如
sort.Slice([]Person{{"A",20}}, ...)会触发cannot slice literal错误;得先赋值给变量再传 - 原地修改,原始切片内容被覆盖,如需保留旧顺序,调用前做浅拷贝:
copy := append([]Person(nil), people...) - 返回
true表示「i应该排在j前面」,升序就写people[i].Age ,降序就换符号或取反
多字段排序别写 if/else
Go 的比较函数只允许单个表达式返回 bool,不能写多行逻辑。靠 && 短路求值自然实现优先级。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 按年龄升序、同龄再按姓名降序:
return people[i].Age people[j].Name) - 浮点字段慎用
==,改用math.Abs(a-b) 避免精度问题 - 字符串长度排序?直接
len(people[i].Name) > len(people[j].Name),sort.Strings完全不管这事
空指针、NaN、稳定性这些坑容易漏
结构体字段是 *string 或 *int 时,闭包里直接访问会 panic:invalid memory address or nil pointer dereference。必须提前判空。
- 字段为指针且可能为
nil,比较前加保护:if people[i].Name == nil || people[j].Name == nil { return people[i].Name != nil } - 浮点字段含
NaN?sort.Slice会把它排到末尾,但如果你手动比较,NaN == NaN永远是false,得用math.IsNaN单独处理 - 需要稳定排序(相等键的元素保持原有相对顺序)?必须换
sort.SliceStable,sort.Slice不保证这点,底层是 pdqsort
最常被忽略的是:字段可导出性、切片是否可寻址、以及多字段排序时把 == 当 用——这三个点一错,要么编译不过,要么运行时 panic,要么结果错得毫无规律。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










