需求描述:调用方通过指定结构体某字段(如示例1中的project_id),后端服务基于该字段排序后将结构返回;
难点:后端视角与前端视角不一样,对于指定的字段,不能直接排序
解决方法:
法1:列举法
法2:反射机制
示例1:
// 带json tag的结构体
type Data struct {
ProjectId string `json:"project_id,omitempty"`
ProjectName string `json:"project_name,omitempty"`
}
// 后端视角
type Data struct {
ProjectId string
ProjectName string
}
// 调用方视角
{
"project_id":"123",
"project_name":"test"
}
列举法:
switch json_tag_name {
case "project_id":
// sort
...
}
优点:直接明了
缺点:不灵活,随着结构体成员的增加,case会变多
反射机制:
实现方式1:通过json tag获取对应成员在结构体中的index
objectIndex := -1
projIType := reflect.TypeOf(data[0]).Elem() // 通过反射获取type定义
for i := 0; i < projIType.NumField(); i++ {
tag := strings.Split(projIType.Field(i).Tag.Get("json"), ",") // json:project_id,omitempty
if len(tag) > 0 {
jsonName := tag[0]
if jsonName == "project_id" {// "project_id"是调用方的入参,可以是结构体任何字段的json tag
objectIndex = i
break
}
}
if objectIndex == -1 { // 指定的json字段有误;必须判断,否则后面的执行会panic
return
}
}
sort.Slice(data, func(i, j int) bool {
projI := reflect.ValueOf(data[i]).Elem()
projJ := reflect.ValueOf(data[j]).Elem()
projIFiled := projI.Field(objectIndex) // It panics if v's Kind is not Struct or i is out of range.
projJFiled := projJ.Field(objectIndex)
return projIFiled.String() > projJFiled.String()// 降序排,可以根据需求灵活改动
})
优点:可以支持指定结构体内任意字段进行排序
缺点:当指定的json tag不在结构体中时,直接使用Field(objectIndex)会panic(It panics if v’s Kind is not Struct or i is out of range.)
实现方式2:通过json tag获取对应变量名;
var objectName string
if len(data) > 0 {
projIType := reflect.TypeOf(data[0]).Elem() // 通过反射获取type定义
for i := 0; i < projIType.NumField(); i++ {
tag := strings.Split(projIType.Field(i).Tag.Get("json"), ",") // project_id,omitempty
if len(tag) > 0 {
jsonName := tag[0]
if jsonName == "project_id" {// "project_id"是调用方的入参,可以是结构体任何字段的json tag
objectName = projIType.Field(i).Name
break
}
}
}
if len(objectName) == 0 { // 指定的json字段有误;没有这个判断,后面的执行也不会panic
return
}
}
sort.Slice(data, func(i, j int) bool {
projI := reflect.ValueOf(data[i]).Elem()
projJ := reflect.ValueOf(data[j]).Elem()
projIFiled := projI.FieldByName(objectName) // It returns the zero Value if no field was found.
projJFiled := projJ.FieldByName(objectName)
return projIFiled.String() > projJFiled.String() // 降序排,可以根据需求灵活改动;需要根据字段类型,此处字段类型为string
})
优点:即使指定的json tag不存在结构体中,获取的变量名为空,直接使用FieldByName(“不存在的变量名”)也不会panic(It returns the zero Value if no field was found)