golang对结构体里的宽字段进行字典序排序
2020-08-08 本文已影响0人
杜子龙
现在业务有一个异步查询的需求,需要把不同的请求缓存起来,需要对同一类请求封装成request struct,放到map的key中,如果请求中都是基础类型还好说,可以直接使用golang原生的序列化包,对struct序列化之后,是会自动按照struct中字段的字典序排序。但这里有个问题,就是前端请求中的某个字段是个json宽字段,因此这里就不适合直接使用序列化工具,需要遍历struct,找出其中的宽字段,先反序列化再序列化即可。但这样比较麻烦,需要事先知道结构体中有哪些宽字段,以及结构体里嵌套结构体里的宽字段,所以这里基于反射实现了此功能,目前只接受入参为指针,后续待优化。
func SortedStruct(i interface{}){//暂时只接受指针
v := reflect.ValueOf(i)
if v.Kind() == reflect.Ptr{
deepSortedStruct(v)
}else{//TODO 这里有bug
SortedStruct(&i)
}
}
func deepSortedStruct(v reflect.Value){
switch v.Kind() {
case reflect.String:
v.SetString(sortStr(v.String()))
case reflect.Array:
for i := 0; i < v.Len(); i++{
deepSortedStruct(v.Index(i))
}
case reflect.Slice:
if v.IsNil(){
return
}
for i := 0; i < v.Len(); i++{
deepSortedStruct(v.Index(i))
}
case reflect.Interface:
if v.IsNil(){
return
}
deepSortedStruct(v.Elem())
case reflect.Ptr:
deepSortedStruct(v.Elem())
case reflect.Struct:
for i := 0; i < v.NumField(); i++{
deepSortedStruct(v.Field(i))
}
case reflect.Map:
if v.IsNil(){
return
}
for _, key := range v.MapKeys(){
deepSortedStruct(v.MapIndex(key))
}
}
}
func sortStr(str string)string{
var tmp interface{}
err := json.Unmarshal([]byte(str), &tmp)
if err != nil{
return str
}
bytes, _ := json.Marshal(tmp)
return string(bytes)
}