go语言动态返回所需字段

42 阅读2分钟
package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "reflect"
)

func JsonPrint(student interface{}) interface{} {
    jsonData, err := json.MarshalIndent(student, "", "  ")
    if err != nil {
       fmt.Println("JSON 编码失败:", err)
       return nil
    }
    return string(jsonData)
}

type Student struct {
    AAA string
    BBB string
    CCC string
}

func main() {
    // 传入返回值字符串
    fields := []string{"CCC"}

    // 创建切片数据集
    student := []Student{
       {AAA: "1", BBB: "John Doe", CCC: "20"},
       {AAA: "2", BBB: "Jane Doe", CCC: "22"},
       {AAA: "3", BBB: "Mike Smith", CCC: "23"},
    }
    data, _ := FormatConversion(student, fields)
    fmt.Println("切片返回到前端的数据: ", data)

    // 创建单个数据集
    student2 := Student{
       AAA: "John Doe",
       BBB: "20",
       CCC: "Male",
    }
    data2, _ := FormatConversion(student2, fields)
    fmt.Println("结构体返回到前端的数据: ", data2)
}

// 不用看后面那两个函数,只需要调用这一个函数即可
// 这个函数引用了下面两个函数的逻辑
// 当前函数值用于判断传入的参数是结构体还是切片,然后执行后面对应的函数处理相关逻辑
func FormatConversion(base interface{}, fields []string) (interface{}, error) {
    value := reflect.ValueOf(base)

    switch value.Kind() {
    case reflect.Struct:
       // 传入参数为结构体,对切片进行处理
       // 参数一为传入的结构体,参数二为所需要返回的字段
       dynamicStruct, err := createDynamicStruct(base, fields)
       if err != nil {
          fmt.Println(err)
          return nil, err
       }
       // 打印返回的数据
       fmt.Println("打印转换后的数据" , JsonPrint(dynamicStruct))
       return dynamicStruct, nil
    case reflect.Slice:
       // 传入参数为切片,对切片进行处理
       // 参数一为传入的切片,参数二为所需要返回的字段
       dynamicStruct, err := createDynamicStructsFromSlice(base, fields)
       if err != nil {
          fmt.Println(err)
          return nil, err
       }
       // 打印转换后的数据
       fmt.Println("打印转换后的数据" , JsonPrint(dynamicStruct))
       return dynamicStruct, nil
    default:
       fmt.Println("未知类型") // 既不是结构体也不是切片
       return nil, errors.New("参数一传入格式有误,请传入结构体或者切片")
    }
}

// 传入一个结构体和字符串数组,返回一个动态结构体
// 同时在处理切片时也会用到该函数
func createDynamicStruct(base interface{}, fields []string) (interface{}, error) {
    baseType := reflect.TypeOf(base)
    if baseType.Kind() != reflect.Struct {
       return nil, fmt.Errorf("expected a struct, got %s", baseType.Kind())
    }

    fieldValues := make([]reflect.Value, 0, len(fields))
    fieldNames := make([]reflect.StructField, 0, len(fields))

    for _, fieldName := range fields {
       field, found := baseType.FieldByName(fieldName)
       if !found {
          return nil, fmt.Errorf("field %s not found in struct", fieldName)
       }
       fieldValues = append(fieldValues, reflect.ValueOf(base).FieldByName(fieldName))
       fieldNames = append(fieldNames, reflect.StructField{
          Name: fieldName,
          Type: field.Type,
          Tag:  field.Tag,
       })
    }

    // 创建一个动态类型,包含所需的字段
    dynamicType := reflect.StructOf(fieldNames)
    dynamicValue := reflect.New(dynamicType).Elem()

    // 设置动态结构体的字段值
    for i, fieldValue := range fieldValues {
       dynamicValue.Field(i).Set(fieldValue)
    }

    return dynamicValue.Interface(), nil
}

// 传入一个切片和字符串数组,返回一个动态结构体切片
func createDynamicStructsFromSlice(baseSlice interface{}, fields []string) ([]interface{}, error) {
    sliceValue := reflect.ValueOf(baseSlice)
    if sliceValue.Kind() != reflect.Slice {
       return nil, fmt.Errorf("expected a slice, got %s", sliceValue.Kind())
    }

    baseElemType := sliceValue.Type().Elem()
    if baseElemType.Kind() != reflect.Struct {
       return nil, fmt.Errorf("slice elements are not structs")
    }

    var dynamicSlice []interface{}
    for i := 0; i < sliceValue.Len(); i++ {
       elem := sliceValue.Index(i)
       dynamicStruct, err := createDynamicStruct(elem.Interface(), fields)
       if err != nil {
          return nil, err
       }
       dynamicSlice = append(dynamicSlice, dynamicStruct)
    }

    return dynamicSlice, nil
}

上面代码可以直接放到main.go运行一下,运行结果如下:

在这里插入图片描述