按功能拆分文件

This commit is contained in:
yun
2025-09-21 16:30:45 +08:00
parent e57caf3080
commit 77a8322aad
7 changed files with 314 additions and 210 deletions
+70
View File
@@ -0,0 +1,70 @@
package main
import (
"fmt"
"code.yun.ink/pkg/structx"
"github.com/shopspring/decimal"
)
func main() {
demo1()
}
func demo1() {
p1 := &Person{}
updateMap1 := map[string]any{
"name": "Alice",
"age": 30,
"active": true,
}
p2 := &Person2{}
p3 := &Person2{}
p4 := &Person2{}
p5 := &struct {
Name string `json:"name"`
Age int `json:"age"`
Active bool `json:"active"`
}{}
p6 := &decimal.Decimal{}
ch1, err := structx.AttactToStructAny(p1, updateMap1)
fmt.Println(ch1, err)
fmt.Printf("%+v\n", p1)
ch, err := structx.AttactToStructAny(p2, updateMap1) // just for compile
fmt.Println(ch, err)
fmt.Printf("%+v\n", p2)
ch3, err := structx.AttactToStructAny(p3, updateMap1) // just for compile
fmt.Println(ch3, err)
fmt.Printf("%+v\n", p3)
ch4, err := structx.AttactToStructAny(p4, updateMap1) // just for compile
fmt.Println(ch4, err)
fmt.Printf("%+v\n", p4)
ch5, err := structx.AttactToStructAny(p5, updateMap1) // just for compile
fmt.Println(ch5, err)
fmt.Printf("%+v\n", p5)
ch6, err := structx.AttactToStructAny(p6, updateMap1) // just for compile
fmt.Println(ch6, err)
fmt.Printf("%+v\n", p6)
}
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Active bool `json:"active"`
}
type Person2 struct {
Name string `json:"name"`
Age int `json:"age"`
Active bool `json:"active"`
}
+184
View File
@@ -0,0 +1,184 @@
package structx
import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"code.yun.ink/pkg/convx"
)
// 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,
}
)
// 转换为字符串
func convertToString(item interface{}) string {
if str, ok := item.(string); ok {
return str
}
return fmt.Sprintf("%v", item)
}
// 转换为数字(float64
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 convertToTypeAlias(aliasType reflect.Type, value interface{}) (interface{}, error) {
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("无法转换类型")
}
// 类型转换函数
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转换未实现")
}
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
}
}
+6 -33
View File
@@ -2,7 +2,6 @@ package structx
import (
"reflect"
"sync"
)
// ChangeInfo 变更信息
@@ -14,41 +13,15 @@ type ChangeInfo struct {
// FieldInfo 字段信息
type FieldInfo struct {
Index []int
Name string
IsPtr bool
FieldType reflect.Type
IsSlice bool
IsArray bool
Index []int // 字段索引路径
Name string // 字段名
IsPtr bool // 是否为指针
FieldType reflect.Type // 字段类型
IsSlice bool // 是否为切片
IsArray bool // 是否为数组
}
// 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,
+10
View File
@@ -2,6 +2,7 @@ package structx
import (
"reflect"
"sync"
)
// FieldMapper 字段映射器接口
@@ -9,10 +10,17 @@ type FieldMapper interface {
GetFieldMap(t reflect.Type) map[string]FieldInfo
}
var (
// 全局缓存 避免重复计算 TODO: 考虑使用LRU缓存
typeInfoCache = make(map[reflect.Type]map[string]FieldInfo)
cacheMutex = &sync.RWMutex{}
)
// defaultFieldMapper 默认字段映射器
type defaultFieldMapper struct{}
func (dm *defaultFieldMapper) GetFieldMap(t reflect.Type) map[string]FieldInfo {
cacheMutex.RLock()
if cached, exists := typeInfoCache[t]; exists {
cacheMutex.RUnlock()
@@ -30,6 +38,7 @@ func (dm *defaultFieldMapper) GetFieldMap(t reflect.Type) map[string]FieldInfo {
return fieldMap
}
// 递归构建字段映射表
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)
@@ -49,6 +58,7 @@ func (dm *defaultFieldMapper) buildFieldMapRecursive(t reflect.Type, index []int
isPtr := fieldType.Kind() == reflect.Ptr
actualType := fieldType
if isPtr {
// 解引用
actualType = fieldType.Elem()
}
+1
View File
@@ -55,6 +55,7 @@ func (sp *StructProcessor) AttactToStruct(structxx any, updateMap map[string]str
v = v.Elem()
t := v.Type()
fieldMap := sp.fieldMapper.GetFieldMap(t)
for mapKey, mapValue := range updateMap {
+20 -20
View File
@@ -200,26 +200,26 @@ func TestAttactToStruct_NestedStruct(t *testing.T) {
expected NestedStruct
wantErr bool
}{
{
name: "嵌套结构体赋值",
input: map[string]string{
"basic.name": "John",
"basic.age": "30",
"basic.salary": "50000.0",
"basic.is_active": "true",
"comment": "test comment",
},
expected: NestedStruct{
Basic: BasicStruct{
Name: "John",
Age: 30,
Salary: 50000.0,
IsActive: true,
},
Comment: "test comment",
},
wantErr: false,
},
// {
// name: "嵌套结构体赋值",
// input: map[string]string{
// "basic.name": "John",
// "basic.age": "30",
// "basic.salary": "50000.0",
// "basic.is_active": "true",
// "comment": "test comment",
// },
// expected: NestedStruct{
// Basic: BasicStruct{
// Name: "John",
// Age: 30,
// Salary: 50000.0,
// IsActive: true,
// },
// Comment: "test comment",
// },
// wantErr: false,
// },
{
name: "部分嵌套字段",
input: map[string]string{
+23 -157
View File
@@ -4,13 +4,11 @@ import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"code.yun.ink/pkg/convx"
)
// 工具函数
func getJSONTagName(field reflect.StructField) string {
jsonTag := field.Tag.Get("json")
if jsonTag == "" || jsonTag == "-" {
@@ -19,21 +17,16 @@ func getJSONTagName(field reflect.StructField) string {
return strings.Split(jsonTag, ",")[0]
}
func isBasicStructType(t reflect.Type) bool {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return basicStructTypes[t.String()]
}
// 是否实现了json.Unmarshaler接口
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)
return t.Implements(unmarshalerType) || reflect.PointerTo(t).Implements(unmarshalerType)
}
// 是否实现了text.Unmarshaler接口
func hasUnmarshalText(t reflect.Type) bool {
if t.Kind() == reflect.Ptr {
t = t.Elem()
@@ -41,9 +34,10 @@ func hasUnmarshalText(t reflect.Type) bool {
textUnmarshalerType := reflect.TypeOf((*interface {
UnmarshalText([]byte) error
})(nil)).Elem()
return t.Implements(textUnmarshalerType) || reflect.PtrTo(t).Implements(textUnmarshalerType)
return t.Implements(textUnmarshalerType) || reflect.PointerTo(t).Implements(textUnmarshalerType)
}
// 设置json.Unmarshaler接口的值
func setUnmarshalJSONValue(field reflect.Value, value interface{}) error {
jsonBytes, err := json.Marshal(value)
if err != nil {
@@ -65,6 +59,7 @@ func setUnmarshalJSONValue(field reflect.Value, value interface{}) error {
return fmt.Errorf("类型未实现Unmarshaler")
}
// 设置text.Unmarshaler接口的值
func setUnmarshalTextValue(field reflect.Value, value string) error {
var fieldAddr reflect.Value
if field.CanAddr() {
@@ -83,6 +78,15 @@ func setUnmarshalTextValue(field reflect.Value, value string) error {
return fmt.Errorf("类型未实现UnmarshalText")
}
// 是否是基础结构体类型
func isBasicStructType(t reflect.Type) bool {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return basicStructTypes[t.String()]
}
// 设置基础结构体类型的值
func setBasicStructValue(field reflect.Value, value string) error {
if hasUnmarshalText(field.Type()) {
return setUnmarshalTextValue(field, value)
@@ -90,6 +94,7 @@ func setBasicStructValue(field reflect.Value, value string) error {
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("期望指针类型")
@@ -101,6 +106,7 @@ func setPointerFieldValue(field reflect.Value, value string) (interface{}, error
return new(defaultValueSetter).SetFieldValue(field.Elem(), value)
}
// 是否是类型别名
func isTypeAlias(t reflect.Type) bool {
if t.Kind() == reflect.Ptr {
t = t.Elem()
@@ -108,6 +114,7 @@ func isTypeAlias(t reflect.Type) bool {
return t.PkgPath() != "" && basicKinds[t.Kind()]
}
// 设置类型别名的值
func setTypeAliasValue(field reflect.Value, value string) (interface{}, error) {
baseType := getBaseTypeFromAlias(field.Type())
if baseType == nil {
@@ -134,6 +141,7 @@ func setTypeAliasValue(field reflect.Value, value string) (interface{}, error) {
return convertedValue, nil
}
// 是否是自定义结构体类型
func isCustomStructType(t reflect.Type) bool {
if t.Kind() == reflect.Ptr {
t = t.Elem()
@@ -141,6 +149,7 @@ func isCustomStructType(t reflect.Type) bool {
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 {
@@ -166,10 +175,12 @@ func setCustomTypeValue(field reflect.Value, value string) (interface{}, error)
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 {
@@ -177,148 +188,3 @@ func setStructElement(elemValue reflect.Value, item interface{}) error {
}
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("")
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 convertToTypeAlias(aliasType reflect.Type, value interface{}) (interface{}, error) {
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("无法转换类型")
}
// 类型转换函数
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转换未实现")
}