1112 lines
28 KiB
Go
1112 lines
28 KiB
Go
package structx
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"reflect"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"code.yun.ink/pkg/convx"
|
||
"github.com/spf13/cast"
|
||
)
|
||
|
||
type ChangeInfo struct {
|
||
Old string `json:"old"`
|
||
New string `json:"new"`
|
||
Val interface{} `json:"val"`
|
||
}
|
||
|
||
// 统一的类型转换函数
|
||
type converterFunc func(reflect.Value, string) (interface{}, error)
|
||
|
||
var typeConverters = map[reflect.Kind]converterFunc{
|
||
reflect.Bool: convertBool,
|
||
reflect.Int: convertInt[int],
|
||
reflect.Int8: convertInt[int8],
|
||
reflect.Int16: convertInt[int16],
|
||
reflect.Int32: convertInt[int32],
|
||
reflect.Int64: convertInt[int64],
|
||
reflect.Uint: convertUint[uint],
|
||
reflect.Uint8: convertUint[uint8],
|
||
reflect.Uint16: convertUint[uint16],
|
||
reflect.Uint32: convertUint[uint32],
|
||
reflect.Uint64: convertUint[uint64],
|
||
reflect.Float32: convertFloat[float32],
|
||
reflect.Float64: convertFloat[float64],
|
||
reflect.String: convertString,
|
||
reflect.Slice: convertSlice,
|
||
reflect.Array: convertArray,
|
||
reflect.Map: convertMap,
|
||
}
|
||
|
||
// 缓存类型信息以避免重复反射操作
|
||
var typeInfoCache = make(map[reflect.Type]map[string]fieldInfo)
|
||
|
||
// AttactToStructAny 将 map[string]interface{} 类型的值附加到结构体中
|
||
func AttactToStructAny(structxx interface{}, updateMap map[string]interface{}) (map[string]ChangeInfo, error) {
|
||
stringMap := make(map[string]string, len(updateMap))
|
||
for k, v := range updateMap {
|
||
str, err := cast.ToStringE(v)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("转换键 %s 的值失败: %w", k, err)
|
||
}
|
||
stringMap[k] = str
|
||
}
|
||
|
||
return AttactToStruct(structxx, stringMap)
|
||
}
|
||
|
||
|
||
// AttactToStruct 将 map 的数据赋值到结构体中,支持嵌套结构体和指针
|
||
func AttactToStruct(structxx interface{}, updateMap map[string]string) (map[string]ChangeInfo, error) {
|
||
v := reflect.ValueOf(structxx)
|
||
if v.Kind() != reflect.Ptr || v.IsNil() {
|
||
return nil, fmt.Errorf("structxx 需要是非空指针")
|
||
}
|
||
|
||
changeMap := make(map[string]ChangeInfo)
|
||
v = v.Elem()
|
||
|
||
// 获取结构体类型信息
|
||
t := v.Type()
|
||
fieldMap := buildFieldMap(t)
|
||
|
||
for mapKey, mapValue := range updateMap {
|
||
fieldInfo, exists := fieldMap[mapKey]
|
||
if !exists {
|
||
return nil, fmt.Errorf("字段 %s 不存在", mapKey)
|
||
}
|
||
|
||
// 获取字段值,正确处理指针
|
||
field := v
|
||
for i, idx := range fieldInfo.Index {
|
||
// 确保当前字段是结构体类型(不是指针)
|
||
if field.Kind() == reflect.Ptr {
|
||
if field.IsNil() {
|
||
newValue := reflect.New(field.Type().Elem())
|
||
field.Set(newValue)
|
||
}
|
||
field = field.Elem()
|
||
}
|
||
|
||
if field.Kind() != reflect.Struct {
|
||
return nil, fmt.Errorf("字段索引 %v 不是结构体类型", fieldInfo.Index[:i+1])
|
||
}
|
||
|
||
field = field.Field(idx)
|
||
if !field.IsValid() {
|
||
return nil, fmt.Errorf("字段索引 %v 无效", fieldInfo.Index[:i+1])
|
||
}
|
||
}
|
||
|
||
// 现在 field 是最终的字段值,可能是指针或非指针
|
||
var actualField reflect.Value
|
||
if field.Kind() == reflect.Ptr {
|
||
if field.IsNil() {
|
||
newValue := reflect.New(field.Type().Elem())
|
||
field.Set(newValue)
|
||
}
|
||
actualField = field.Elem()
|
||
} else {
|
||
actualField = field
|
||
}
|
||
|
||
if !actualField.IsValid() {
|
||
continue
|
||
}
|
||
|
||
// 处理切片和数组类型
|
||
if fieldInfo.IsSlice || fieldInfo.IsArray {
|
||
err := processSliceOrArrayField(actualField, mapValue, mapKey)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("处理切片/数组字段 %s 失败: %w", mapKey, err)
|
||
}
|
||
continue
|
||
}
|
||
|
||
// 处理嵌套结构体
|
||
if actualField.Kind() == reflect.Struct && !isBasicStructType(actualField.Type()) {
|
||
nestedChanges, err := processNestedStruct(actualField, mapValue, mapKey)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("处理嵌套结构体字段 %s 失败: %w", mapKey, err)
|
||
}
|
||
for nestedKey, change := range nestedChanges {
|
||
changeMap[nestedKey] = change
|
||
}
|
||
continue
|
||
}
|
||
|
||
if !actualField.CanSet() {
|
||
continue
|
||
}
|
||
|
||
// 处理基本类型
|
||
oldValueStr, err := cast.ToStringE(actualField.Interface())
|
||
if err != nil {
|
||
oldValueStr = fmt.Sprintf("%v", actualField.Interface())
|
||
}
|
||
|
||
newValue, err := setFieldValue(actualField, mapValue)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("设置字段 %s 的值失败: %w", mapKey, err)
|
||
}
|
||
|
||
newValueStr, err := cast.ToStringE(newValue)
|
||
if err != nil {
|
||
newValueStr = fmt.Sprintf("%v", newValue)
|
||
}
|
||
|
||
changeMap[mapKey] = ChangeInfo{
|
||
Old: oldValueStr,
|
||
New: newValueStr,
|
||
Val: newValue,
|
||
}
|
||
}
|
||
|
||
return changeMap, nil
|
||
}
|
||
|
||
|
||
// 处理切片和数组字段
|
||
func processSliceOrArrayField(field reflect.Value, value string, fieldKey string) error {
|
||
// 尝试解析JSON数组
|
||
var jsonData []interface{}
|
||
if err := json.Unmarshal([]byte(value), &jsonData); err != nil {
|
||
return fmt.Errorf("字段 %s 的值必须是JSON数组格式: %w", fieldKey, err)
|
||
}
|
||
|
||
fieldType := field.Type()
|
||
elemType := fieldType.Elem()
|
||
|
||
// 创建新的切片或数组
|
||
var newContainer reflect.Value
|
||
|
||
if fieldType.Kind() == reflect.Slice {
|
||
newContainer = reflect.MakeSlice(fieldType, len(jsonData), len(jsonData))
|
||
} else if fieldType.Kind() == reflect.Array {
|
||
if len(jsonData) != fieldType.Len() {
|
||
return fmt.Errorf("字段 %s 的数组长度不匹配: 期望 %d, 实际 %d",
|
||
fieldKey, fieldType.Len(), len(jsonData))
|
||
}
|
||
newContainer = reflect.New(fieldType).Elem()
|
||
} else {
|
||
return fmt.Errorf("字段 %s 不是切片或数组类型", fieldKey)
|
||
}
|
||
|
||
// 填充数据
|
||
for i, item := range jsonData {
|
||
elemValue := newContainer.Index(i)
|
||
err := setSliceElementValue(elemValue, item, elemType)
|
||
if err != nil {
|
||
return fmt.Errorf("设置切片/数组元素失败: %w", err)
|
||
}
|
||
}
|
||
|
||
field.Set(newContainer)
|
||
return nil
|
||
}
|
||
|
||
// 设置切片/数组元素的值
|
||
func setSliceElementValue(elemValue reflect.Value, item interface{}, elemType reflect.Type) error {
|
||
// 处理指针类型的元素
|
||
if elemType.Kind() == reflect.Ptr {
|
||
if elemValue.IsNil() {
|
||
elemValue.Set(reflect.New(elemType.Elem()))
|
||
}
|
||
return setSliceElementValue(elemValue.Elem(), item, elemType.Elem())
|
||
}
|
||
|
||
// 检查是否实现了 UnmarshalJSON 方法
|
||
if hasUnmarshalJSON(elemType) {
|
||
return setUnmarshalJSONValue(elemValue, item)
|
||
}
|
||
|
||
// 根据元素类型进行转换
|
||
switch elemType.Kind() {
|
||
case reflect.String:
|
||
elemValue.SetString(convertToString(item))
|
||
|
||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||
num, err := convertToFloat64(item)
|
||
if err != nil {
|
||
return fmt.Errorf("无法将 %v 转换为整型: %w", item, err)
|
||
}
|
||
elemValue.SetInt(int64(num))
|
||
|
||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||
num, err := convertToFloat64(item)
|
||
if err != nil {
|
||
return fmt.Errorf("无法将 %v 转换为无符号整型: %w", item, err)
|
||
}
|
||
elemValue.SetUint(uint64(num))
|
||
|
||
case reflect.Float32, reflect.Float64:
|
||
num, err := convertToFloat64(item)
|
||
if err != nil {
|
||
return fmt.Errorf("无法将 %v 转换为浮点型: %w", item, err)
|
||
}
|
||
elemValue.SetFloat(num)
|
||
|
||
case reflect.Bool:
|
||
b, ok := item.(bool)
|
||
if !ok {
|
||
return fmt.Errorf("无法将 %v 转换为布尔型", item)
|
||
}
|
||
elemValue.SetBool(b)
|
||
|
||
case reflect.Struct:
|
||
if isBasicStructType(elemType) {
|
||
return setBasicStructElement(elemValue, item, elemType)
|
||
}
|
||
return setStructElement(elemValue, item)
|
||
|
||
default:
|
||
return fmt.Errorf("不支持的切片元素类型: %s", elemType.Kind())
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// 辅助转换函数
|
||
func convertToString(item interface{}) string {
|
||
if str, ok := item.(string); ok {
|
||
return str
|
||
}
|
||
return fmt.Sprintf("%v", item)
|
||
}
|
||
|
||
func convertToFloat64(item interface{}) (float64, error) {
|
||
switch v := item.(type) {
|
||
case float64:
|
||
return v, nil
|
||
case int, int32, int64:
|
||
return float64(reflect.ValueOf(v).Int()), nil
|
||
case uint, uint32, uint64:
|
||
return float64(reflect.ValueOf(v).Uint()), nil
|
||
case float32:
|
||
return float64(v), nil
|
||
default:
|
||
return 0, fmt.Errorf("无法转换为数字")
|
||
}
|
||
}
|
||
|
||
// 设置结构体元素
|
||
func setStructElement(elemValue reflect.Value, item interface{}) error {
|
||
jsonBytes, err := json.Marshal(item)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return json.Unmarshal(jsonBytes, elemValue.Addr().Interface())
|
||
}
|
||
|
||
// 设置基本结构体元素
|
||
func setBasicStructElement(elemValue reflect.Value, item interface{}, elemType reflect.Type) error {
|
||
return setStructElement(elemValue, item)
|
||
}
|
||
|
||
// getFieldByIndexSafe 安全地通过索引路径获取字段,处理嵌套指针
|
||
func getFieldByIndexSafe(v reflect.Value, index []int) (reflect.Value, error) {
|
||
if len(index) == 0 {
|
||
return v, nil
|
||
}
|
||
|
||
field := v.Field(index[0])
|
||
if !field.IsValid() {
|
||
return reflect.Value{}, fmt.Errorf("字段索引 %d 无效", index[0])
|
||
}
|
||
|
||
// 递归解引用指针
|
||
for field.Kind() == reflect.Ptr {
|
||
if field.IsNil() {
|
||
elemType := field.Type().Elem()
|
||
newValue := reflect.New(elemType)
|
||
field.Set(newValue)
|
||
}
|
||
field = field.Elem()
|
||
}
|
||
|
||
if len(index) > 1 {
|
||
return getFieldByIndexSafe(field, index[1:])
|
||
}
|
||
|
||
return field, nil
|
||
}
|
||
|
||
// 构建字段映射表
|
||
type fieldInfo struct {
|
||
Index []int
|
||
Name string
|
||
IsPtr bool
|
||
FieldType reflect.Type
|
||
IsSlice bool
|
||
IsArray bool
|
||
}
|
||
|
||
func buildFieldMap(t reflect.Type) map[string]fieldInfo {
|
||
// 检查缓存
|
||
if cached, exists := typeInfoCache[t]; exists {
|
||
return cached
|
||
}
|
||
|
||
fieldMap := make(map[string]fieldInfo)
|
||
buildFieldMapRecursive(t, []int{}, fieldMap, "")
|
||
|
||
// 缓存结果
|
||
typeInfoCache[t] = fieldMap
|
||
return fieldMap
|
||
}
|
||
|
||
func buildFieldMapRecursive(t reflect.Type, index []int, fieldMap map[string]fieldInfo, prefix string) {
|
||
for i := 0; i < t.NumField(); i++ {
|
||
field := t.Field(i)
|
||
if !field.IsExported() {
|
||
continue
|
||
}
|
||
|
||
currentIndex := append(index, i)
|
||
jsonTag := getJSONTagName(field)
|
||
|
||
fullKey := jsonTag
|
||
if prefix != "" {
|
||
fullKey = prefix + "." + jsonTag
|
||
}
|
||
|
||
fieldType := field.Type
|
||
isPtr := fieldType.Kind() == reflect.Ptr
|
||
actualType := fieldType
|
||
if isPtr {
|
||
actualType = fieldType.Elem()
|
||
}
|
||
|
||
// 处理切片和数组类型
|
||
if actualType.Kind() == reflect.Slice || actualType.Kind() == reflect.Array {
|
||
fieldMap[fullKey] = fieldInfo{
|
||
Index: currentIndex,
|
||
Name: field.Name,
|
||
IsPtr: isPtr,
|
||
FieldType: fieldType,
|
||
IsSlice: actualType.Kind() == reflect.Slice,
|
||
IsArray: actualType.Kind() == reflect.Array,
|
||
}
|
||
continue
|
||
}
|
||
|
||
// 处理嵌套结构体
|
||
if actualType.Kind() == reflect.Struct && !isBasicStructType(actualType) {
|
||
buildFieldMapRecursive(actualType, currentIndex, fieldMap, fullKey)
|
||
}
|
||
|
||
fieldMap[fullKey] = fieldInfo{
|
||
Index: currentIndex,
|
||
Name: field.Name,
|
||
IsPtr: isPtr,
|
||
FieldType: fieldType,
|
||
}
|
||
}
|
||
}
|
||
|
||
func getJSONTagName(field reflect.StructField) string {
|
||
jsonTag := field.Tag.Get("json")
|
||
if jsonTag == "" || jsonTag == "-" {
|
||
return field.Name
|
||
}
|
||
return strings.Split(jsonTag, ",")[0]
|
||
}
|
||
|
||
// 判断是否为基本结构体类型
|
||
func isBasicStructType(t reflect.Type) bool {
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
// 检查常见的基本结构体类型
|
||
switch {
|
||
case t.PkgPath() == "time" && t.Name() == "Time":
|
||
return true
|
||
case t.PkgPath() == "github.com/shopspring/decimal" && t.Name() == "Decimal":
|
||
return true
|
||
case strings.HasPrefix(t.String(), "sql.Null"):
|
||
return true
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
// 检查类型是否实现了 UnmarshalJSON 方法
|
||
func hasUnmarshalJSON(t reflect.Type) bool {
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
unmarshalerType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
|
||
return t.Implements(unmarshalerType) || reflect.PtrTo(t).Implements(unmarshalerType)
|
||
}
|
||
|
||
// 检查类型是否实现了 UnmarshalText 方法
|
||
func hasUnmarshalText(t reflect.Type) bool {
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
textUnmarshalerType := reflect.TypeOf((*interface {
|
||
UnmarshalText([]byte) error
|
||
})(nil)).Elem()
|
||
return t.Implements(textUnmarshalerType) || reflect.PtrTo(t).Implements(textUnmarshalerType)
|
||
}
|
||
|
||
// 使用 UnmarshalJSON 方法设置值
|
||
func setUnmarshalJSONValue(field reflect.Value, value interface{}) error {
|
||
jsonBytes, err := json.Marshal(value)
|
||
if err != nil {
|
||
return fmt.Errorf("序列化值失败: %w", err)
|
||
}
|
||
|
||
var fieldAddr reflect.Value
|
||
if field.CanAddr() {
|
||
fieldAddr = field.Addr()
|
||
} else {
|
||
temp := reflect.New(field.Type())
|
||
temp.Elem().Set(field)
|
||
fieldAddr = temp
|
||
}
|
||
|
||
if unmarshaler, ok := fieldAddr.Interface().(json.Unmarshaler); ok {
|
||
return unmarshaler.UnmarshalJSON(jsonBytes)
|
||
}
|
||
|
||
return fmt.Errorf("类型 %s 未实现 json.Unmarshaler", field.Type())
|
||
}
|
||
|
||
// 使用 UnmarshalText 方法设置值
|
||
func setUnmarshalTextValue(field reflect.Value, value string) error {
|
||
var fieldAddr reflect.Value
|
||
if field.CanAddr() {
|
||
fieldAddr = field.Addr()
|
||
} else {
|
||
temp := reflect.New(field.Type())
|
||
temp.Elem().Set(field)
|
||
fieldAddr = temp
|
||
}
|
||
|
||
if unmarshaler, ok := fieldAddr.Interface().(interface {
|
||
UnmarshalText([]byte) error
|
||
}); ok {
|
||
return unmarshaler.UnmarshalText([]byte(value))
|
||
}
|
||
|
||
return fmt.Errorf("类型 %s 未实现 UnmarshalText", field.Type())
|
||
}
|
||
|
||
// 处理嵌套结构体
|
||
func processNestedStruct(field reflect.Value, value string, parentKey string) (map[string]ChangeInfo, error) {
|
||
changeMap := make(map[string]ChangeInfo)
|
||
|
||
var structValue reflect.Value
|
||
if field.Kind() == reflect.Ptr {
|
||
if field.IsNil() {
|
||
newValue := reflect.New(field.Type().Elem())
|
||
field.Set(newValue)
|
||
}
|
||
structValue = field.Elem()
|
||
} else {
|
||
structValue = field
|
||
}
|
||
|
||
if !structValue.IsValid() || structValue.Kind() != reflect.Struct {
|
||
return nil, fmt.Errorf("无效的结构体字段")
|
||
}
|
||
|
||
// 尝试解析为JSON对象
|
||
var nestedMap map[string]interface{}
|
||
if err := json.Unmarshal([]byte(value), &nestedMap); err == nil {
|
||
stringMap := make(map[string]string, len(nestedMap))
|
||
for k, v := range nestedMap {
|
||
str, err := cast.ToStringE(v)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("转换嵌套字段 %s 的值失败: %w", k, err)
|
||
}
|
||
stringMap[k] = str
|
||
}
|
||
|
||
nestedChanges, err := AttactToStruct(structValue.Addr().Interface(), stringMap)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
for key, change := range nestedChanges {
|
||
changeMap[parentKey+"."+key] = change
|
||
}
|
||
return changeMap, nil
|
||
}
|
||
|
||
// 尝试直接设置结构体值
|
||
if hasUnmarshalJSON(structValue.Type()) || isBasicStructType(structValue.Type()) {
|
||
oldValueStr, _ := cast.ToStringE(field.Interface())
|
||
|
||
err := setBasicStructValue(structValue, value)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("设置基本结构体值失败: %w", err)
|
||
}
|
||
|
||
newValueStr, _ := cast.ToStringE(field.Interface())
|
||
changeMap[parentKey] = ChangeInfo{
|
||
Old: oldValueStr,
|
||
New: newValueStr,
|
||
Val: structValue.Interface(),
|
||
}
|
||
return changeMap, nil
|
||
}
|
||
|
||
return nil, fmt.Errorf("嵌套结构体值必须是有效的JSON格式或基本结构体类型")
|
||
}
|
||
|
||
// 设置基本结构体的值
|
||
func setBasicStructValue(field reflect.Value, value string) error {
|
||
if hasUnmarshalText(field.Type()) {
|
||
return setUnmarshalTextValue(field, value)
|
||
}
|
||
return json.Unmarshal([]byte(value), field.Addr().Interface())
|
||
}
|
||
|
||
// 设置字段值
|
||
func setFieldValue(field reflect.Value, value string) (interface{}, error) {
|
||
fieldType := field.Type()
|
||
|
||
// 优先检查接口实现
|
||
if hasUnmarshalJSON(fieldType) {
|
||
err := setUnmarshalJSONValue(field, value)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("UnmarshalJSON 失败: %w", err)
|
||
}
|
||
return field.Interface(), nil
|
||
}
|
||
|
||
if hasUnmarshalText(fieldType) {
|
||
err := setUnmarshalTextValue(field, value)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("UnmarshalText 失败: %w", err)
|
||
}
|
||
return field.Interface(), nil
|
||
}
|
||
|
||
// 处理指针类型
|
||
if fieldType.Kind() == reflect.Ptr {
|
||
return setPointerFieldValue(field, value)
|
||
}
|
||
|
||
// 处理类型别名(如 type CustomString string)
|
||
if isTypeAlias(fieldType) {
|
||
return setTypeAliasValue(field, value)
|
||
}
|
||
|
||
// 处理自定义类型(有包路径的结构体类型)
|
||
if isCustomStructType(fieldType) {
|
||
return setCustomTypeValue(field, value)
|
||
}
|
||
|
||
// 处理基本类型
|
||
converter, exists := typeConverters[fieldType.Kind()]
|
||
if !exists {
|
||
return nil, fmt.Errorf("不支持的类型: %s", fieldType.Kind().String())
|
||
}
|
||
|
||
result, err := converter(field, value)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
field.Set(reflect.ValueOf(result))
|
||
return result, nil
|
||
}
|
||
|
||
// 设置类型别名的值
|
||
func setTypeAliasValue(field reflect.Value, value string) (interface{}, error) {
|
||
fieldType := field.Type()
|
||
|
||
// 获取基础类型
|
||
baseType := getBaseTypeFromAlias(fieldType)
|
||
if baseType == nil {
|
||
return nil, fmt.Errorf("无法获取类型别名的基础类型: %s", fieldType.String())
|
||
}
|
||
|
||
// 使用基础类型的转换器
|
||
converter, exists := typeConverters[baseType.Kind()]
|
||
if !exists {
|
||
return nil, fmt.Errorf("不支持的基础类型: %s", baseType.Kind().String())
|
||
}
|
||
|
||
// 创建基础类型的临时值
|
||
baseValue := reflect.New(baseType).Elem()
|
||
result, err := converter(baseValue, value)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 将基础类型值转换为类型别名
|
||
convertedValue, err := convertToTypeAlias(fieldType, result)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
field.Set(reflect.ValueOf(convertedValue))
|
||
return convertedValue, nil
|
||
}
|
||
|
||
// 将基础类型值转换为类型别名
|
||
func convertToTypeAlias(aliasType reflect.Type, value interface{}) (interface{}, error) {
|
||
// valueType := reflect.TypeOf(value)
|
||
|
||
// 处理指针类型的类型别名
|
||
if aliasType.Kind() == reflect.Ptr {
|
||
elemType := aliasType.Elem()
|
||
|
||
// 创建新的指针实例
|
||
newValue := reflect.New(elemType)
|
||
elemValue := newValue.Elem()
|
||
|
||
// 转换值
|
||
converted, err := convertValueToType(value, elemType)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
elemValue.Set(reflect.ValueOf(converted))
|
||
|
||
return newValue.Interface(), nil
|
||
}
|
||
|
||
// 处理非指针类型的类型别名
|
||
return convertValueToType(value, aliasType)
|
||
}
|
||
|
||
// 将值转换为指定类型
|
||
func convertValueToType(value interface{}, targetType reflect.Type) (interface{}, error) {
|
||
valueType := reflect.TypeOf(value)
|
||
|
||
if valueType.AssignableTo(targetType) {
|
||
return value, nil
|
||
}
|
||
|
||
if valueType.ConvertibleTo(targetType) {
|
||
return reflect.ValueOf(value).Convert(targetType).Interface(), nil
|
||
}
|
||
|
||
return nil, fmt.Errorf("无法将 %v 转换为 %v", valueType, targetType)
|
||
}
|
||
|
||
// 检查是否为自定义结构体类型
|
||
func isCustomStructType(t reflect.Type) bool {
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
// 排除基本类型
|
||
if t.PkgPath() == "" {
|
||
return false
|
||
}
|
||
|
||
// 排除已知的基本结构体类型
|
||
if isBasicStructType(t) {
|
||
return false
|
||
}
|
||
|
||
// 排除类型别名
|
||
if isTypeAlias(t) {
|
||
return false
|
||
}
|
||
|
||
// 排除接口类型
|
||
if t.Kind() == reflect.Interface {
|
||
return false
|
||
}
|
||
|
||
// 必须是结构体类型
|
||
return t.Kind() == reflect.Struct
|
||
}
|
||
|
||
|
||
|
||
// 获取类型别名的基础类型
|
||
func getBaseTypeFromAlias(aliasType reflect.Type) reflect.Type {
|
||
if aliasType.Kind() == reflect.Ptr {
|
||
aliasType = aliasType.Elem()
|
||
}
|
||
|
||
// 根据类型别名的种类返回对应的基础类型
|
||
switch aliasType.Kind() {
|
||
case reflect.String:
|
||
return reflect.TypeOf("")
|
||
case reflect.Int:
|
||
return reflect.TypeOf(int(0))
|
||
case reflect.Int8:
|
||
return reflect.TypeOf(int8(0))
|
||
case reflect.Int16:
|
||
return reflect.TypeOf(int16(0))
|
||
case reflect.Int32:
|
||
return reflect.TypeOf(int32(0))
|
||
case reflect.Int64:
|
||
return reflect.TypeOf(int64(0))
|
||
case reflect.Uint:
|
||
return reflect.TypeOf(uint(0))
|
||
case reflect.Uint8:
|
||
return reflect.TypeOf(uint8(0))
|
||
case reflect.Uint16:
|
||
return reflect.TypeOf(uint16(0))
|
||
case reflect.Uint32:
|
||
return reflect.TypeOf(uint32(0))
|
||
case reflect.Uint64:
|
||
return reflect.TypeOf(uint64(0))
|
||
case reflect.Float32:
|
||
return reflect.TypeOf(float32(0))
|
||
case reflect.Float64:
|
||
return reflect.TypeOf(float64(0))
|
||
case reflect.Bool:
|
||
return reflect.TypeOf(false)
|
||
default:
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// 检测是否为自定义类型
|
||
func isCustomType(t reflect.Type) bool {
|
||
// 排除基本类型
|
||
if t.PkgPath() == "" {
|
||
return false
|
||
}
|
||
|
||
// 排除已知的基本结构体类型
|
||
if isBasicStructType(t) {
|
||
return false
|
||
}
|
||
|
||
// 排除接口类型
|
||
if t.Kind() == reflect.Interface {
|
||
return false
|
||
}
|
||
|
||
// 排除基础类型的别名
|
||
if isBasicTypeAlias(t) {
|
||
return false
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
// 检查是否为类型别名(如 type CustomString string)
|
||
func isTypeAlias(t reflect.Type) bool {
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
// 类型别名有包路径且是基本类型
|
||
basicKinds := map[reflect.Kind]bool{
|
||
reflect.String: true,
|
||
reflect.Int: true,
|
||
reflect.Int8: true,
|
||
reflect.Int16: true,
|
||
reflect.Int32: true,
|
||
reflect.Int64: true,
|
||
reflect.Uint: true,
|
||
reflect.Uint8: true,
|
||
reflect.Uint16: true,
|
||
reflect.Uint32: true,
|
||
reflect.Uint64: true,
|
||
reflect.Float32: true,
|
||
reflect.Float64: true,
|
||
reflect.Bool: true,
|
||
}
|
||
|
||
return t.PkgPath() != "" && basicKinds[t.Kind()]
|
||
}
|
||
|
||
// 检查是否为基本类型的别名(如 type CustomString string)
|
||
func isBasicTypeAlias(t reflect.Type) bool {
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
// 检查是否为基本类型的别名
|
||
basicKinds := map[reflect.Kind]bool{
|
||
reflect.String: true,
|
||
reflect.Int: true,
|
||
reflect.Int8: true,
|
||
reflect.Int16: true,
|
||
reflect.Int32: true,
|
||
reflect.Int64: true,
|
||
reflect.Uint: true,
|
||
reflect.Uint8: true,
|
||
reflect.Uint16: true,
|
||
reflect.Uint32: true,
|
||
reflect.Uint64: true,
|
||
reflect.Float32: true,
|
||
reflect.Float64: true,
|
||
reflect.Bool: true,
|
||
}
|
||
|
||
return basicKinds[t.Kind()]
|
||
}
|
||
|
||
// 处理自定义类型
|
||
func setCustomTypeValue(field reflect.Value, value string) (interface{}, error) {
|
||
// 检查是否实现了TextUnmarshaler接口
|
||
if hasUnmarshalText(field.Type()) {
|
||
err := setUnmarshalTextValue(field, value)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return field.Interface(), nil
|
||
}
|
||
|
||
// 对于其他自定义结构体类型,尝试JSON解析
|
||
var jsonData interface{}
|
||
if err := json.Unmarshal([]byte(value), &jsonData); err != nil {
|
||
return nil, fmt.Errorf("无法解析JSON: %w", err)
|
||
}
|
||
|
||
jsonBytes, err := json.Marshal(jsonData)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if err := json.Unmarshal(jsonBytes, field.Addr().Interface()); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return field.Interface(), nil
|
||
|
||
// // 对于其他自定义类型,我们需要获取其基础类型并进行转换
|
||
// baseType := getBaseType(field.Type())
|
||
// if baseType == nil {
|
||
// return nil, fmt.Errorf("不支持的自定义类型: %s", field.Type().String())
|
||
// }
|
||
|
||
// // 创建基础类型的值并进行转换
|
||
// baseValue := reflect.New(baseType).Elem()
|
||
|
||
// // 使用对应的类型转换器
|
||
// converter, exists := typeConverters[baseType.Kind()]
|
||
// if !exists {
|
||
// return nil, fmt.Errorf("不支持的基础类型: %s", baseType.Kind().String())
|
||
// }
|
||
|
||
// result, err := converter(baseValue, value)
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
|
||
// // 将基础类型值转换回自定义类型
|
||
// convertedValue, err := convertToCustomType(field.Type(), result)
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
|
||
// field.Set(reflect.ValueOf(convertedValue))
|
||
// return convertedValue, nil
|
||
}
|
||
|
||
// 将基础类型值转换为自定义类型
|
||
func convertToCustomType(customType reflect.Type, value interface{}) (interface{}, error) {
|
||
valueType := reflect.TypeOf(value)
|
||
|
||
// 处理指针类型的自定义类型
|
||
if customType.Kind() == reflect.Ptr {
|
||
elemType := customType.Elem()
|
||
|
||
// 创建新的指针实例
|
||
newValue := reflect.New(elemType)
|
||
elemValue := newValue.Elem()
|
||
|
||
// 尝试将值设置到元素
|
||
if valueType.AssignableTo(elemType) {
|
||
elemValue.Set(reflect.ValueOf(value))
|
||
} else if reflect.ValueOf(value).Type().ConvertibleTo(elemType) {
|
||
converted := reflect.ValueOf(value).Convert(elemType)
|
||
elemValue.Set(converted)
|
||
} else {
|
||
// 对于自定义类型,尝试通过字符串转换
|
||
if str, ok := value.(string); ok && elemType.Kind() == reflect.String {
|
||
elemValue.SetString(str)
|
||
} else {
|
||
return nil, fmt.Errorf("无法将 %v 转换为 %v", valueType, elemType)
|
||
}
|
||
}
|
||
|
||
return newValue.Interface(), nil
|
||
}
|
||
|
||
// 处理非指针类型的自定义类型
|
||
if valueType.AssignableTo(customType) {
|
||
return value, nil
|
||
}
|
||
|
||
if reflect.ValueOf(value).Type().ConvertibleTo(customType) {
|
||
return reflect.ValueOf(value).Convert(customType).Interface(), nil
|
||
}
|
||
|
||
// 对于字符串到自定义字符串类型的转换
|
||
if str, ok := value.(string); ok && customType.Kind() == reflect.String {
|
||
return reflect.ValueOf(str).Convert(customType).Interface(), nil
|
||
}
|
||
|
||
return nil, fmt.Errorf("无法将 %v 转换为 %v", valueType, customType)
|
||
}
|
||
|
||
// 获取自定义类型的基础类型
|
||
func getBaseType(t reflect.Type) reflect.Type {
|
||
for t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
// 如果是自定义类型(有包路径),获取其底层类型
|
||
if t.PkgPath() != "" {
|
||
// 对于类型别名,我们需要获取其底层的基本类型
|
||
switch t.Kind() {
|
||
case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||
reflect.Float32, reflect.Float64, reflect.Bool:
|
||
// 这是基本类型的别名,返回对应的基本类型
|
||
switch t.Kind() {
|
||
case reflect.String:
|
||
return reflect.TypeOf("")
|
||
case reflect.Int:
|
||
return reflect.TypeOf(int(0))
|
||
case reflect.Int8:
|
||
return reflect.TypeOf(int8(0))
|
||
case reflect.Int16:
|
||
return reflect.TypeOf(int16(0))
|
||
case reflect.Int32:
|
||
return reflect.TypeOf(int32(0))
|
||
case reflect.Int64:
|
||
return reflect.TypeOf(int64(0))
|
||
case reflect.Uint:
|
||
return reflect.TypeOf(uint(0))
|
||
case reflect.Uint8:
|
||
return reflect.TypeOf(uint8(0))
|
||
case reflect.Uint16:
|
||
return reflect.TypeOf(uint16(0))
|
||
case reflect.Uint32:
|
||
return reflect.TypeOf(uint32(0))
|
||
case reflect.Uint64:
|
||
return reflect.TypeOf(uint64(0))
|
||
case reflect.Float32:
|
||
return reflect.TypeOf(float32(0))
|
||
case reflect.Float64:
|
||
return reflect.TypeOf(float64(0))
|
||
case reflect.Bool:
|
||
return reflect.TypeOf(false)
|
||
}
|
||
default:
|
||
// 对于其他自定义类型,尝试获取其底层类型
|
||
if t.Kind() == reflect.Struct {
|
||
// 如果是结构体,检查是否有可转换的基础类型
|
||
if field := getBaseTypeField(t); field.Name != "" {
|
||
return field.Type
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// 获取结构体中可能的基础类型字段
|
||
func getBaseTypeField(t reflect.Type) reflect.StructField {
|
||
if t.Kind() != reflect.Struct || t.NumField() != 1 {
|
||
return reflect.StructField{}
|
||
}
|
||
|
||
field := t.Field(0)
|
||
basicKinds := map[reflect.Kind]bool{
|
||
reflect.String: true,
|
||
reflect.Int: true,
|
||
reflect.Int8: true,
|
||
reflect.Int16: true,
|
||
reflect.Int32: true,
|
||
reflect.Int64: true,
|
||
reflect.Uint: true,
|
||
reflect.Uint8: true,
|
||
reflect.Uint16: true,
|
||
reflect.Uint32: true,
|
||
reflect.Uint64: true,
|
||
reflect.Float32: true,
|
||
reflect.Float64: true,
|
||
reflect.Bool: true,
|
||
}
|
||
|
||
if basicKinds[field.Type.Kind()] && field.IsExported() {
|
||
return field
|
||
}
|
||
|
||
return reflect.StructField{}
|
||
}
|
||
|
||
|
||
// 处理指针类型的字段
|
||
func setPointerFieldValue(field reflect.Value, value string) (interface{}, error) {
|
||
if field.Kind() != reflect.Ptr {
|
||
return nil, fmt.Errorf("setPointerFieldValue: 期望指针类型,得到 %s", field.Kind())
|
||
}
|
||
|
||
if field.IsNil() {
|
||
elemType := field.Type().Elem()
|
||
newValue := reflect.New(elemType)
|
||
field.Set(newValue)
|
||
}
|
||
return setFieldValue(field.Elem(), value)
|
||
}
|
||
|
||
// 类型转换函数(保持不变)
|
||
func convertBool(field reflect.Value, value string) (interface{}, error) {
|
||
return convx.ToBool(value)
|
||
}
|
||
|
||
func convertInt[T int | int8 | int16 | int32 | int64](field reflect.Value, value string) (interface{}, error) {
|
||
bits := field.Type().Bits()
|
||
intVal, err := strconv.ParseInt(value, 10, bits)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return T(intVal), nil
|
||
}
|
||
|
||
func convertUint[T uint | uint8 | uint16 | uint32 | uint64](field reflect.Value, value string) (interface{}, error) {
|
||
bits := field.Type().Bits()
|
||
uintVal, err := strconv.ParseUint(value, 10, bits)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return T(uintVal), nil
|
||
}
|
||
|
||
func convertFloat[T float32 | float64](field reflect.Value, value string) (interface{}, error) {
|
||
bits := field.Type().Bits()
|
||
floatVal, err := strconv.ParseFloat(value, bits)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return T(floatVal), nil
|
||
}
|
||
|
||
func convertString(field reflect.Value, value string) (interface{}, error) {
|
||
return value, nil
|
||
}
|
||
|
||
func convertSlice(field reflect.Value, value string) (interface{}, error) {
|
||
var result []interface{}
|
||
if err := json.Unmarshal([]byte(value), &result); err != nil {
|
||
return nil, err
|
||
}
|
||
return result, nil
|
||
}
|
||
|
||
func convertArray(field reflect.Value, value string) (interface{}, error) {
|
||
var result []interface{}
|
||
if err := json.Unmarshal([]byte(value), &result); err != nil {
|
||
return nil, err
|
||
}
|
||
return result, nil
|
||
}
|
||
|
||
func convertMap(field reflect.Value, value string) (interface{}, error) {
|
||
return nil, fmt.Errorf("map转换未实现")
|
||
} |