需求描述:调用方通过指定结构体某字段(如示例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)