Skip to content
go 语言动态返回所需字段
go
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运行一下,运行结果如下:

在这里插入图片描述