sort map struct
为什么要有它
Go 的 map 本身没有顺序,而且每次遍历的顺序都是随机的——你没法「对 map 排序」。当业务需要「按某个 struct 字段把 map 里的值排好序再返回」时,只能先把值取出来放进切片,再对切片排序。
sort map struct 把这套动作封装成两个泛型函数:
MapStrcutSort:把map[KEY]VALUE的值抽成[]VALUE,再按指定字段排序后返回。SliceStrcutSort:直接对[]VALUE按 struct 的某个字段排序(借助reflect取字段,支持int/float/string)。
代码
package helper
import (
"reflect"
"sort"
)
// MapStrcutSort 对map进行排序,值为struct类型
func MapStrcutSort[KEY comparable, VALUE any](m map[KEY]VALUE, fieldName string) []VALUE {
var ret = make([]VALUE, 0)
for _, d := range m {
ret = append(ret, d)
}
SliceStrcutSort(ret, fieldName)
return ret
}
// SliceStrcutSort 对slice进行排序,值为struct类型
func SliceStrcutSort[VALUE any](s []VALUE, fieldName string) {
defer func() {
if r := recover(); r != nil {
}
}()
sliceValue := reflect.ValueOf(s)
less := func(i, j int) bool {
v1 := reflect.Indirect(sliceValue.Index(i))
v2 := reflect.Indirect(sliceValue.Index(j))
if v1.Kind() != reflect.Struct || v2.Kind() != reflect.Struct {
return false
}
valueI := v1.FieldByName(fieldName)
valueJ := v2.FieldByName(fieldName)
switch valueI.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return valueI.Int() < valueJ.Int()
case reflect.Float32, reflect.Float64:
return valueI.Float() < valueJ.Float()
case reflect.String:
return valueI.String() < valueJ.String()
default:
return false
}
}
sort.Slice(s, less)
}
要点
- map 不可排序,只能转切片:
MapStrcutSort先for range把值摊平到[]VALUE,再交给SliceStrcutSort排序,返回的已经是「排好序的切片」,原 map 不会被改动(也无从改动)。 - 用
reflect按字段名取值:FieldByName(fieldName)按名字拿字段,所以传入的fieldName必须是导出字段(首字母大写);非导出字段reflect取不到,会走default分支当成相等处理。 - 支持的类型:
int系列、float系列、string。其他类型(bool、嵌套 struct、time.Time等)在switch里落到default,less返回false——也就是被当成「相等」,排序对这些字段实际上不生效。 reflect.Indirect兼容指针元素:如果切片里放的是*Struct,Indirect会解引用到 struct;放的是值类型则原样返回,两种都能排。- panic 被静默吞掉:
defer recover()保证字段名写错、或切片为空等情况下不崩,但代价是「排序失败也不会报错」——排查时需注意:万一没排上序,大概率是fieldName拼错或字段类型不支持。 - 两个陷阱提醒:
sort.Slice不是稳定排序;若多个元素目标字段相等,它们的相对顺序不保证。需要确定性再排序就用sort.SliceStable。- 只对单个字段排序,不支持
A.B这样的嵌套路径。
这两个函数的名字(
MapStrcutSort/SliceStrcutSort)按原 helper 包命名保留;如想更规范可改名MapStructSort/SliceStructSort。泛型约束KEY comparable是 map key 的硬性要求,VALUE any则可接受任意结构体。