代码片段: RequestToStruct

工作中写到的一段通用性较高的代码,根据 结构体 A 中的 tag 匹配数据到 结构体B

package controller

import (
	"bibibi/logger"
	"errors"
	"reflect"
	"strconv"

	"github.com/shopspring/decimal"
)

type Request struct {
}

// ToStruct 将请求结构体 `req` 中包含 `to` 标签的字段赋值给 `target` 结构体
func ToStruct(req interface{}, target interface{}) error {
	targetType := reflect.TypeOf(target)
	if targetType.Kind() != reflect.Ptr {
		return errors.New("target must be reflect.Ptr")
	}

	reqType := reflect.TypeOf(req)
	reqValue := reflect.ValueOf(req)

	targetValue := reflect.ValueOf(target)
	targetElem := targetValue.Elem()
	for i := 0; i < reqType.NumField(); i++ {
		reqField := reqType.Field(i) //
		toName := reqField.Tag.Get("to")
		if toName == "" || toName == "-" {
			continue
		}
		reqVal := reqValue.FieldByName(reqField.Name)
		//fmt.Println("请求结构体---> i:", i, ",toName :", toName, ",reqVal:", reqVal)
		targetField := targetElem.FieldByName(toName)
		if !targetField.CanSet() {
			logger.L.Error("targetField.CanSet() is false!")
			continue
		}
		switch targetField.Kind() { // 按类型给目标变量设置值
		case reflect.String:
			if reqVal.Kind() == reflect.String {
				targetField.SetString(reqVal.String())
			} else if reqVal.Kind() == reflect.Int {
				targetField.SetString(strconv.Itoa(int(reqVal.Int())))
			}
		case reflect.Int:
			if reqVal.Kind() == reflect.String {
				num, e := strconv.Atoi(reqVal.String())
				if e != nil {
					logger.L.Error("RequestTo(): strconv.Atoi() fail:", e)
					continue
				}
				targetField.SetInt(int64(num))
			} else if reqVal.Kind() == reflect.Int {
				targetField.SetInt(reqVal.Int())
			}
		case reflect.Struct:
			if targetField.Type().String() != "decimal.Decimal" {
				logger.L.Error("RequestTo() `to`对应目标字段是 `decimal.Decimal` 以外的结构体:", targetField.Type().String())
				continue
			}
			if reqVal.Kind() == reflect.String {
				_v, e := decimal.NewFromString(reqVal.String())
				if e != nil {
					logger.L.Error("RequestTo(): decimal.NewFromString() fail:", e)
					continue
				}
				targetField.Set(reflect.ValueOf(_v))
			}
		default:
			logger.L.Error("RequestTo(): targetField.Kind()-->", targetField.Kind())
		}
	}
	return nil
}