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)
}
上一篇下一篇

猜你喜欢

热点阅读