From 5caada1cb872d0046097140f2de3020a4f5736b8 Mon Sep 17 00:00:00 2001 From: wln32 Date: Tue, 14 Jan 2025 14:31:11 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=96=87=E4=BB=B6=E5=90=8D=E4=BC=98=E5=8C=96?= =?UTF-8?q?=202.=E5=AD=98=E5=82=A8=E6=8E=A5=E5=8F=A3=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E8=BD=AC=E6=8D=A2=E7=94=B1map=E6=94=B9=E4=B8=BAslice?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E4=BF=9D=E8=AF=81=E7=A8=B3=E5=AE=9A=E6=80=A7?= =?UTF-8?q?=203.=E5=85=A8=E5=B1=80=E5=8F=98=E9=87=8FdefaultConfig=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E6=96=B9=E6=B3=95=E8=B0=83=E7=94=A8DefaultConvertConf?= =?UTF-8?q?ig()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/gconv/gconv_convert_config.go | 4 ++ util/gconv/gconv_maptomap.go | 2 +- util/gconv/gconv_scan.go | 2 +- util/gconv/gconv_struct.go | 8 ++-- util/gconv/gconv_structs.go | 2 +- util/gconv/gconv_z_bench_struct_test.go | 2 +- .../{group_config.go => convert_config.go} | 40 ++++++++++--------- ...up_config.go => convert_config_default.go} | 0 8 files changed, 34 insertions(+), 26 deletions(-) rename util/gconv/internal/structcache/{group_config.go => convert_config.go} (84%) rename util/gconv/internal/structcache/{default_group_config.go => convert_config_default.go} (100%) diff --git a/util/gconv/gconv_convert_config.go b/util/gconv/gconv_convert_config.go index 29a9bf71f22..ffd1fd4719e 100644 --- a/util/gconv/gconv_convert_config.go +++ b/util/gconv/gconv_convert_config.go @@ -14,6 +14,10 @@ type ConvertConfig = structcache.ConvertConfig var defaultConfig = structcache.GetDefaultConfig() +func DefaultConvertConfig() *ConvertConfig { + return defaultConfig +} + func NewConvertConfig(name string) *ConvertConfig { return structcache.NewConvertConfig(name) } diff --git a/util/gconv/gconv_maptomap.go b/util/gconv/gconv_maptomap.go index 543c002ec75..15cd240e6bc 100644 --- a/util/gconv/gconv_maptomap.go +++ b/util/gconv/gconv_maptomap.go @@ -100,7 +100,7 @@ func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]s switch pointerValueKind { case reflect.Map, reflect.Struct: if err = doStruct( - paramsRv.MapIndex(key).Interface(), mapValue, keyToAttributeNameMapping, "", defaultConfig, + paramsRv.MapIndex(key).Interface(), mapValue, keyToAttributeNameMapping, "", DefaultConvertConfig(), ); err != nil { return err } diff --git a/util/gconv/gconv_scan.go b/util/gconv/gconv_scan.go index 90e18b88cd0..99df2aaa5fc 100644 --- a/util/gconv/gconv_scan.go +++ b/util/gconv/gconv_scan.go @@ -20,7 +20,7 @@ import ( // // TODO change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`. func Scan(srcValue interface{}, dstPointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) { - return scan(defaultConfig, srcValue, dstPointer, paramKeyToAttrMap...) + return scan(DefaultConvertConfig(), srcValue, dstPointer, paramKeyToAttrMap...) } func scan(config *ConvertConfig, srcValue interface{}, dstPointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) { diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 6446208793f..dbe2635b6de 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -40,7 +40,7 @@ func Struct(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[st // specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping. // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. func StructTag(params interface{}, pointer interface{}, priorityTag string) (err error) { - return doStruct(params, pointer, nil, priorityTag, defaultConfig) + return doStruct(params, pointer, nil, priorityTag, DefaultConvertConfig()) } // doStruct is the core internal converting function for any data to struct. @@ -491,7 +491,7 @@ func bindVarToReflectValue( case reflect.Struct: // Recursively converting for struct attribute. - if err = doStruct(value, structFieldValue, nil, "", defaultConfig); err != nil { + if err = doStruct(value, structFieldValue, nil, "", DefaultConvertConfig()); err != nil { // Note there's reflect conversion mechanism here. structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) } @@ -524,7 +524,7 @@ func bindVarToReflectValue( elem = reflect.New(elemType).Elem() } if elem.Kind() == reflect.Struct { - if err = doStruct(reflectValue.Index(i).Interface(), elem, nil, "", defaultConfig); err == nil { + if err = doStruct(reflectValue.Index(i).Interface(), elem, nil, "", DefaultConvertConfig()); err == nil { converted = true } } @@ -574,7 +574,7 @@ func bindVarToReflectValue( elem = reflect.New(elemType).Elem() } if elem.Kind() == reflect.Struct { - if err = doStruct(value, elem, nil, "", defaultConfig); err == nil { + if err = doStruct(value, elem, nil, "", DefaultConvertConfig()); err == nil { converted = true } } diff --git a/util/gconv/gconv_structs.go b/util/gconv/gconv_structs.go index dd3b4a3d473..9a8e87c2a02 100644 --- a/util/gconv/gconv_structs.go +++ b/util/gconv/gconv_structs.go @@ -28,7 +28,7 @@ func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string] // specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping. // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. func StructsTag(params interface{}, pointer interface{}, priorityTag string) (err error) { - return doStructs(params, pointer, nil, priorityTag, defaultConfig) + return doStructs(params, pointer, nil, priorityTag, DefaultConvertConfig()) } // doStructs converts any slice to given struct slice. diff --git a/util/gconv/gconv_z_bench_struct_test.go b/util/gconv/gconv_z_bench_struct_test.go index 0eb45261936..5a2027f4de8 100644 --- a/util/gconv/gconv_z_bench_struct_test.go +++ b/util/gconv/gconv_z_bench_struct_test.go @@ -92,7 +92,7 @@ func Benchmark_Struct_Basic(b *testing.B) { func Benchmark_doStruct_Fields8_Basic_MapToStruct(b *testing.B) { for i := 0; i < b.N; i++ { - doStruct(structMapFields8, structPointer8, map[string]string{}, "", defaultConfig) + doStruct(structMapFields8, structPointer8, map[string]string{}, "", DefaultConvertConfig()) } } diff --git a/util/gconv/internal/structcache/group_config.go b/util/gconv/internal/structcache/convert_config.go similarity index 84% rename from util/gconv/internal/structcache/group_config.go rename to util/gconv/internal/structcache/convert_config.go index bae482cb2a4..2363d0236cd 100644 --- a/util/gconv/internal/structcache/group_config.go +++ b/util/gconv/internal/structcache/convert_config.go @@ -13,19 +13,23 @@ import ( type convertFn = func(from any, to reflect.Value) error +type interfaceTypeConvert struct { + typ reflect.Type + fn convertFn +} + type ConvertConfig struct { name string parseConvertFuncs map[reflect.Type]convertFn - interfaceConvertFuncs map[reflect.Type]convertFn + interfaceConvertFuncs []interfaceTypeConvert // map[reflect.Type]*CachedStructInfo cachedStructsInfoMap sync.Map } func NewConvertConfig(name string) *ConvertConfig { return &ConvertConfig{ - name: name, - parseConvertFuncs: make(map[reflect.Type]convertFn), - interfaceConvertFuncs: make(map[reflect.Type]convertFn), + name: name, + parseConvertFuncs: make(map[reflect.Type]convertFn), } } @@ -55,13 +59,18 @@ func (cf *ConvertConfig) RegisterInterfaceTypeConvertFunc(typ reflect.Type, f co if typ.NumMethod() == 0 { panic("Please register using the [RegisterTypeConvertFunc] function") } - cf.interfaceConvertFuncs[typ] = f + cf.interfaceConvertFuncs = append(cf.interfaceConvertFuncs, + interfaceTypeConvert{ + typ: typ, + fn: f, + }, + ) } func (cf *ConvertConfig) checkTypeImplInterface(typ reflect.Type) convertFn { - for inter, fn := range cf.interfaceConvertFuncs { - if typ.Implements(inter) { - return fn + for _, inter := range cf.interfaceConvertFuncs { + if typ.Implements(inter.typ) { + return inter.fn } } return nil @@ -105,9 +114,6 @@ func (cf *ConvertConfig) getTypeConvertFunc(typ reflect.Type) (fn convertFn) { // TODO is value type typ.Addr typ = reflect.PointerTo(typ) fn = cf.checkTypeImplInterface(typ) - if fn != nil { - return ptrConvertFunc(ptr, fn) - } } if fn != nil { fn = ptrConvertFunc(ptr, fn) @@ -116,16 +122,14 @@ func (cf *ConvertConfig) getTypeConvertFunc(typ reflect.Type) (fn convertFn) { } func ptrConvertFunc(ptr int, fn convertFn) convertFn { - if ptr > 0 { - return ptrConvertFunc(ptr-1, getPtrConvertFunc(fn)) + for i := 0; i < ptr; i++ { + fn = getPtrConvertFunc(fn) } return fn } -func getPtrConvertFunc( - convertFunc convertFn, -) convertFn { - if convertFunc == nil { +func getPtrConvertFunc(fn convertFn) convertFn { + if fn == nil { panic("The conversion function cannot be empty") } return func(from any, to reflect.Value) error { @@ -134,6 +138,6 @@ func getPtrConvertFunc( } // from = nil // to = nil ?? - return convertFunc(from, to.Elem()) + return fn(from, to.Elem()) } } diff --git a/util/gconv/internal/structcache/default_group_config.go b/util/gconv/internal/structcache/convert_config_default.go similarity index 100% rename from util/gconv/internal/structcache/default_group_config.go rename to util/gconv/internal/structcache/convert_config_default.go