From 0e0f076fc41d040bd75adf0e4b08a696fcb70cd6 Mon Sep 17 00:00:00 2001 From: Yun Date: Sun, 21 Sep 2025 00:40:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- structx.go | 1236 ++++++++++++++++++++-------------------------------- 1 file changed, 466 insertions(+), 770 deletions(-) diff --git a/structx.go b/structx.go index eba7f68..29418f0 100644 --- a/structx.go +++ b/structx.go @@ -6,6 +6,7 @@ import ( "reflect" "strconv" "strings" + "sync" "code.yun.ink/pkg/convx" "github.com/spf13/cast" @@ -17,34 +18,97 @@ type ChangeInfo struct { 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, +// FieldMapper 字段映射器接口 +type FieldMapper interface { + GetFieldMap(t reflect.Type) map[string]FieldInfo } -// 缓存类型信息以避免重复反射操作 -var typeInfoCache = make(map[reflect.Type]map[string]fieldInfo) +// ValueSetter 值设置器接口 +type ValueSetter interface { + SetFieldValue(field reflect.Value, value string) (interface{}, error) + SetSliceElementValue(elemValue reflect.Value, item interface{}, elemType reflect.Type) error +} -// AttactToStructAny 将 map[string]interface{} 类型的值附加到结构体中 -func AttactToStructAny(structxx interface{}, updateMap map[string]interface{}) (map[string]ChangeInfo, error) { +// converterFunc 类型转换函数 +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, + } + + typeInfoCache = make(map[reflect.Type]map[string]FieldInfo) + cacheMutex = &sync.RWMutex{} + + basicStructTypes = map[string]bool{ + "time.Time": true, + "github.com/shopspring/decimal.Decimal": true, + "sql.NullString": true, + "sql.NullInt64": true, + "sql.NullBool": true, + "sql.NullFloat64": true, + } + + 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, + } +) + +// FieldInfo 字段信息 +type FieldInfo struct { + Index []int + Name string + IsPtr bool + FieldType reflect.Type + IsSlice bool + IsArray bool +} + +// StructProcessor 结构体处理器 +type StructProcessor struct { + fieldMapper FieldMapper + valueSetter ValueSetter +} + +// NewStructProcessor 创建新的结构体处理器 +func NewStructProcessor() *StructProcessor { + return &StructProcessor{ + fieldMapper: &defaultFieldMapper{}, + valueSetter: &defaultValueSetter{}, + } +} + +// AttactToStructAny 将 map[string]interface{} 转换为字符串映射并调用 AttactToStruct +func (sp *StructProcessor) 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) @@ -53,13 +117,11 @@ func AttactToStructAny(structxx interface{}, updateMap map[string]interface{}) ( } stringMap[k] = str } - - return AttactToStruct(structxx, stringMap) + return sp.AttactToStruct(structxx, stringMap) } - -// AttactToStruct 将 map 的数据赋值到结构体中,支持嵌套结构体和指针 -func AttactToStruct(structxx interface{}, updateMap map[string]string) (map[string]ChangeInfo, error) { +// AttactToStruct 将映射数据赋值到结构体中 +func (sp *StructProcessor) 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 需要是非空指针") @@ -68,9 +130,8 @@ func AttactToStruct(structxx interface{}, updateMap map[string]string) (map[stri changeMap := make(map[string]ChangeInfo) v = v.Elem() - // 获取结构体类型信息 t := v.Type() - fieldMap := buildFieldMap(t) + fieldMap := sp.fieldMapper.GetFieldMap(t) for mapKey, mapValue := range updateMap { fieldInfo, exists := fieldMap[mapKey] @@ -78,56 +139,37 @@ func AttactToStruct(structxx interface{}, updateMap map[string]string) (map[stri 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, err := sp.getFieldByPath(v, fieldInfo.Index) + if err != nil { + return nil, fmt.Errorf("获取字段 %s 失败: %w", mapKey, err) } - // 现在 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() { + if !field.IsValid() { continue } - // 处理切片和数组类型 + // 处理指针字段 + if fieldInfo.IsPtr { + if field.Kind() != reflect.Ptr { + return nil, fmt.Errorf("字段 %s 应该是指针类型", mapKey) + } + if field.IsNil() { + field.Set(reflect.New(fieldInfo.FieldType.Elem())) + } + field = field.Elem() + } + + // 处理切片和数组 if fieldInfo.IsSlice || fieldInfo.IsArray { - err := processSliceOrArrayField(actualField, mapValue, mapKey) - if err != nil { + if err := sp.processSliceOrArrayField(field, mapValue, mapKey); 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 field.Kind() == reflect.Struct && !isBasicStructType(field.Type()) { + nestedChanges, err := sp.processNestedStruct(field, mapValue, mapKey) if err != nil { return nil, fmt.Errorf("处理嵌套结构体字段 %s 失败: %w", mapKey, err) } @@ -137,26 +179,17 @@ func AttactToStruct(structxx interface{}, updateMap map[string]string) (map[stri continue } - if !actualField.CanSet() { + if !field.CanSet() { continue } - // 处理基本类型 - oldValueStr, err := cast.ToStringE(actualField.Interface()) - if err != nil { - oldValueStr = fmt.Sprintf("%v", actualField.Interface()) - } - - newValue, err := setFieldValue(actualField, mapValue) + oldValueStr, _ := cast.ToStringE(field.Interface()) + newValue, err := sp.valueSetter.SetFieldValue(field, 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) - } - + newValueStr, _ := cast.ToStringE(newValue) changeMap[mapKey] = ChangeInfo{ Old: oldValueStr, New: newValueStr, @@ -167,146 +200,8 @@ func AttactToStruct(structxx interface{}, updateMap map[string]string) (map[stri 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) { +// getFieldByPath 通过路径获取字段 +func (sp *StructProcessor) getFieldByPath(v reflect.Value, index []int) (reflect.Value, error) { if len(index) == 0 { return v, nil } @@ -316,197 +211,61 @@ func getFieldByIndexSafe(v reflect.Value, index []int) (reflect.Value, error) { 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.Set(reflect.New(field.Type().Elem())) } field = field.Elem() } if len(index) > 1 { - return getFieldByIndexSafe(field, index[1:]) + return sp.getFieldByPath(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 +// processSliceOrArrayField 处理切片和数组字段 +func (sp *StructProcessor) processSliceOrArrayField(field reflect.Value, value string, fieldKey string) error { + var jsonData []interface{} + if err := json.Unmarshal([]byte(value), &jsonData); err != nil { + return fmt.Errorf("字段 %s 的值必须是JSON数组格式: %w", fieldKey, err) } - fieldMap := make(map[string]fieldInfo) - buildFieldMapRecursive(t, []int{}, fieldMap, "") + fieldType := field.Type() + elemType := fieldType.Elem() - // 缓存结果 - 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 + 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 的数组长度不匹配", fieldKey) } - - 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() + newContainer = reflect.New(fieldType).Elem() } else { - temp := reflect.New(field.Type()) - temp.Elem().Set(field) - fieldAddr = temp + return fmt.Errorf("字段 %s 不是切片或数组类型", fieldKey) } - if unmarshaler, ok := fieldAddr.Interface().(json.Unmarshaler); ok { - return unmarshaler.UnmarshalJSON(jsonBytes) + for i, item := range jsonData { + if err := sp.valueSetter.SetSliceElementValue(newContainer.Index(i), item, elemType); err != nil { + return fmt.Errorf("设置切片元素失败: %w", err) + } } - return fmt.Errorf("类型 %s 未实现 json.Unmarshaler", field.Type()) + field.Set(newContainer) + return nil } -// 使用 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) { +// processNestedStruct 处理嵌套结构体 +func (sp *StructProcessor) 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) + field.Set(reflect.New(field.Type().Elem())) } structValue = field.Elem() } else { @@ -529,7 +288,7 @@ func processNestedStruct(field reflect.Value, value string, parentKey string) (m stringMap[k] = str } - nestedChanges, err := AttactToStruct(structValue.Addr().Interface(), stringMap) + nestedChanges, err := sp.AttactToStruct(structValue.Addr().Interface(), stringMap) if err != nil { return nil, err } @@ -540,12 +299,11 @@ func processNestedStruct(field reflect.Value, value string, parentKey string) (m return changeMap, nil } - // 尝试直接设置结构体值 + // 尝试直接设置值 if hasUnmarshalJSON(structValue.Type()) || isBasicStructType(structValue.Type()) { oldValueStr, _ := cast.ToStringE(field.Interface()) - - err := setBasicStructValue(structValue, value) - if err != nil { + + if err := setBasicStructValue(structValue, value); err != nil { return nil, fmt.Errorf("设置基本结构体值失败: %w", err) } @@ -558,57 +316,112 @@ func processNestedStruct(field reflect.Value, value string, parentKey string) (m return changeMap, nil } - return nil, fmt.Errorf("嵌套结构体值必须是有效的JSON格式或基本结构体类型") + return nil, fmt.Errorf("嵌套结构体值必须是有效的JSON格式") } -// 设置基本结构体的值 -func setBasicStructValue(field reflect.Value, value string) error { - if hasUnmarshalText(field.Type()) { - return setUnmarshalTextValue(field, value) +// defaultFieldMapper 默认字段映射器 +type defaultFieldMapper struct{} + +func (dm *defaultFieldMapper) GetFieldMap(t reflect.Type) map[string]FieldInfo { + cacheMutex.RLock() + if cached, exists := typeInfoCache[t]; exists { + cacheMutex.RUnlock() + return cached } - return json.Unmarshal([]byte(value), field.Addr().Interface()) + cacheMutex.RUnlock() + + fieldMap := make(map[string]FieldInfo) + dm.buildFieldMapRecursive(t, []int{}, fieldMap, "") + + cacheMutex.Lock() + typeInfoCache[t] = fieldMap + cacheMutex.Unlock() + + return fieldMap } -// 设置字段值 -func setFieldValue(field reflect.Value, value string) (interface{}, error) { - fieldType := field.Type() - - // 优先检查接口实现 +func (dm *defaultFieldMapper) 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) { + dm.buildFieldMapRecursive(actualType, currentIndex, fieldMap, fullKey) + } + + fieldMap[fullKey] = FieldInfo{ + Index: currentIndex, + Name: field.Name, + IsPtr: isPtr, + FieldType: fieldType, + } + } +} + +// defaultValueSetter 默认值设置器 +type defaultValueSetter struct{} + +func (ds *defaultValueSetter) 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) + if err := setUnmarshalJSONValue(field, value); 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) + if err := setUnmarshalTextValue(field, value); 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()) + return nil, fmt.Errorf("不支持的类型: %s", fieldType.Kind()) } result, err := converter(field, value) @@ -620,31 +433,174 @@ func setFieldValue(field reflect.Value, value string) (interface{}, error) { 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()) +func (ds *defaultValueSetter) 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 ds.SetSliceElementValue(elemValue.Elem(), item, elemType.Elem()) + } + + 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("无法转换为整型: %w", 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("无法转换为无符号整型: %w", err) + } + elemValue.SetUint(uint64(num)) + case reflect.Float32, reflect.Float64: + num, err := convertToFloat64(item) + if err != nil { + return fmt.Errorf("无法转换为浮点型: %w", err) + } + elemValue.SetFloat(num) + case reflect.Bool: + if b, ok := item.(bool); ok { + elemValue.SetBool(b) + } else { + return fmt.Errorf("无法转换为布尔型") + } + case reflect.Struct: + if isBasicStructType(elemType) { + return setBasicStructElement(elemValue, item) + } + return setStructElement(elemValue, item) + default: + return fmt.Errorf("不支持的切片元素类型: %s", elemType.Kind()) + } + + return nil +} + +// 工具函数 +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() + } + return basicStructTypes[t.String()] +} + +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) +} + +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) +} + +func setUnmarshalJSONValue(field reflect.Value, value interface{}) error { + jsonBytes, err := json.Marshal(value) + if err != nil { + return 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("类型未实现Unmarshaler") +} + +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("类型未实现UnmarshalText") +} + +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 setPointerFieldValue(field reflect.Value, value string) (interface{}, error) { + if field.Kind() != reflect.Ptr { + return nil, fmt.Errorf("期望指针类型") + } + if field.IsNil() { + field.Set(reflect.New(field.Type().Elem())) + } + + + return new(defaultValueSetter).SetFieldValue(field.Elem(), value) +} + +func isTypeAlias(t reflect.Type) bool { + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t.PkgPath() != "" && basicKinds[t.Kind()] +} + +func setTypeAliasValue(field reflect.Value, value string) (interface{}, error) { + baseType := getBaseTypeFromAlias(field.Type()) + if baseType == nil { + return nil, fmt.Errorf("无法获取基础类型") } - // 使用基础类型的转换器 converter, exists := typeConverters[baseType.Kind()] if !exists { - return nil, fmt.Errorf("不支持的基础类型: %s", baseType.Kind().String()) + return nil, fmt.Errorf("不支持的基础类型") } - // 创建基础类型的临时值 baseValue := reflect.New(baseType).Elem() result, err := converter(baseValue, value) if err != nil { return nil, err } - // 将基础类型值转换为类型别名 - convertedValue, err := convertToTypeAlias(fieldType, result) + convertedValue, err := convertToTypeAlias(field.Type(), result) if err != nil { return nil, err } @@ -653,86 +609,77 @@ func setTypeAliasValue(field reflect.Value, value string) (interface{}, error) { 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 + return t.PkgPath() != "" && !isBasicStructType(t) && !isTypeAlias(t) && t.Kind() == reflect.Struct } +func setCustomTypeValue(field reflect.Value, value string) (interface{}, error) { + if hasUnmarshalText(field.Type()) { + if err := setUnmarshalTextValue(field, value); err != nil { + return nil, err + } + return field.Interface(), nil + } + var jsonData interface{} + if err := json.Unmarshal([]byte(value), &jsonData); err != nil { + return nil, 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 +} + +func setBasicStructElement(elemValue reflect.Value, item interface{}) error { + return setStructElement(elemValue, item) +} + +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 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 getBaseTypeFromAlias(aliasType reflect.Type) reflect.Type { if aliasType.Kind() == reflect.Ptr { aliasType = aliasType.Elem() } - // 根据类型别名的种类返回对应的基础类型 switch aliasType.Kind() { case reflect.String: return reflect.TypeOf("") @@ -767,295 +714,35 @@ func getBaseTypeFromAlias(aliasType reflect.Type) reflect.Type { } } -// 检测是否为自定义类型 -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() - - // 创建新的指针实例 +func convertToTypeAlias(aliasType reflect.Type, value interface{}) (interface{}, error) { + if aliasType.Kind() == reflect.Ptr { + elemType := aliasType.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) - } + converted, err := convertValueToType(value, elemType) + if err != nil { + return nil, err } - + elemValue.Set(reflect.ValueOf(converted)) return newValue.Interface(), nil } - // 处理非指针类型的自定义类型 - if valueType.AssignableTo(customType) { + 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 reflect.ValueOf(value).Type().ConvertibleTo(customType) { - return reflect.ValueOf(value).Convert(customType).Interface(), nil + if valueType.ConvertibleTo(targetType) { + return reflect.ValueOf(value).Convert(targetType).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) + return nil, fmt.Errorf("无法转换类型") } -// 获取自定义类型的基础类型 -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) } @@ -1109,4 +796,13 @@ func convertArray(field reflect.Value, value string) (interface{}, error) { func convertMap(field reflect.Value, value string) (interface{}, error) { return nil, fmt.Errorf("map转换未实现") +} + +// 全局函数(保持向后兼容) +func AttactToStructAny(structxx interface{}, updateMap map[string]interface{}) (map[string]ChangeInfo, error) { + return NewStructProcessor().AttactToStructAny(structxx, updateMap) +} + +func AttactToStruct(structxx interface{}, updateMap map[string]string) (map[string]ChangeInfo, error) { + return NewStructProcessor().AttactToStruct(structxx, updateMap) } \ No newline at end of file