From 22e2b78a7c044e59a88c45b9f7bfcb4fcfd0c893 Mon Sep 17 00:00:00 2001 From: guonaihong Date: Wed, 28 Feb 2024 12:01:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 146 ++++++------------------------------ deepcopy.go | 26 +++++-- deepcopy_modify_map_test.go | 113 ++++++++++++++++++++-------- options.go | 12 ++- 4 files changed, 133 insertions(+), 164 deletions(-) diff --git a/README.md b/README.md index 3a53151..0a0f28b 100644 --- a/README.md +++ b/README.md @@ -165,133 +165,33 @@ func main() { deepcopy.CopyEx(&a, &b) } ``` -## 根据某个规则修改dst的值,回调参数的入参是dst的值 -```go -var src = testSrcModifyMap{} - - var need = testDstModifyMap{ - I: 1, - I8: 1, - I16: 1, - I32: 1, - I64: 1, - - U: 1, - U8: 1, - U16: 1, - U32: 1, - U64: 1, - - F32: 1, - F64: 1, - - S: "hello", - B: true, - } - - var dst testDstModifyMap - - err := CopyEx(&dst, &src, WithModifyDstField(map[string]ModifyDstFieldFunc{ - "I": func(v interface{}) interface{} { - return 1 - }, - "I8": func(v interface{}) interface{} { - return int8(1) - }, - "I16": func(v interface{}) interface{} { - return int16(1) - }, - "I32": func(v interface{}) interface{} { - return int32(1) - }, - "I64": func(v interface{}) interface{} { - return int64(1) - }, - - "U": func(v interface{}) interface{} { - return uint(1) - }, - "U8": func(v interface{}) interface{} { - return uint8(1) - }, - "U16": func(v interface{}) interface{} { - return uint16(1) - }, - "U32": func(v interface{}) interface{} { - return uint32(1) - }, - "U64": func(v interface{}) interface{} { - return uint64(1) - }, - "F32": func(v interface{}) interface{} { - return float32(1) - }, - "F64": func(v interface{}) interface{} { - return float64(1) - }, - "S": func(srcArg interface{}) (newDst interface{}) { - return "hello" - }, - "B": func(srcArg interface{}) (newDst interface{}) { - return true - }, - })) - - if err != nil { - t.Errorf("test faild, err:%v", err) - } - if !reflect.DeepEqual(dst, need) { - t.Errorf("test faild, got:%v", dst) - } -``` + ## 根据某个规则修改dst的值,回调参数的入参是src的值 +适合的场景是,比如把src里面的uid字段,拷贝到dst里面的uidString字段 ```go -err := CopyEx(&dst, &src, WithModifySrcField(map[string]ModifySrcFieldFunc{ - "I": func(v interface{}) interface{} { - return 1 - }, - "I8": func(v interface{}) interface{} { - return int8(1) - }, - "I16": func(v interface{}) interface{} { - return int16(1) - }, - "I32": func(v interface{}) interface{} { - return int32(1) - }, - "I64": func(v interface{}) interface{} { - return int64(1) - }, +var src = testSrcModifyMap{ + I: 2, +} - "U": func(v interface{}) interface{} { - return uint(1) - }, - "U8": func(v interface{}) interface{} { - return uint8(1) - }, - "U16": func(v interface{}) interface{} { - return uint16(1) - }, - "U32": func(v interface{}) interface{} { - return uint32(1) - }, - "U64": func(v interface{}) interface{} { - return uint64(1) - }, - "S": func(srcArg interface{}) (newDst interface{}) { - return "hello" - }, - "B": func(srcArg interface{}) (newDst interface{}) { - return true +var need = testDstModifyMap{ + I8: 3, +} + +var dst testDstModifyMap +err := CopyEx(&dst, &src, WithModifySrcField(map[string]ModifySrcValue{ + "I": { + DstFieldName: "I8", SrcFieldName: "I", Callback: func(v interface{}) interface{} { + return int8(v.(int) + 1) }, - })) - - if err != nil { - t.Logf("test faild, err:%v", err) - } - if !reflect.DeepEqual(dst, need) { - t.Logf("test faild, got:%v", dst) - } + }, +})) + +if err != nil { + t.Errorf("test faild, err:%v", err) +} +if !reflect.DeepEqual(dst, need) { + t.Errorf("test faild, got:%v", dst) +} ``` # benchmark 从零实现的deepcopy相比json序列化与反序列化方式拥有更好的性能 diff --git a/deepcopy.go b/deepcopy.go index 19c2232..9775747 100644 --- a/deepcopy.go +++ b/deepcopy.go @@ -228,8 +228,14 @@ func (d *deepCopy) cpyStruct(dst, src reflect.Value, fieldName string, depth int continue } + name := sf.Name + if d.modifySrcMap != nil { + if v, ok := d.modifySrcMap[sf.Name]; ok { + name = v.DstFieldName + } + } // 使用src的字段名在dst里面取出reflect.Value值 - dstValue := dst.FieldByName(sf.Name) + dstValue := dst.FieldByName(name) // dst没有src里面所有的字段,跳过 if !dstValue.IsValid() { @@ -314,18 +320,22 @@ func isBaseType(kind reflect.Kind) bool { // 其他类型 func (d *deepCopy) cpyDefault(dst, src reflect.Value, fieldName string, depth int) error { - if dst.Kind() != src.Kind() { - return nil - } - if d.modifySrcMap != nil { + if v, ok := d.modifySrcMap[fieldName]; ok { + + newInterfaceValue := v.Callback(src.Interface()) + newValue := reflect.ValueOf(newInterfaceValue) + if newValue.Kind() == dst.Kind() { + dst.Set(newValue) + } - if f, ok := d.modifySrcMap[fieldName]; ok { - newValue := f(src.Interface()) - dst.Set(reflect.ValueOf(newValue)) return nil } } + if dst.Kind() != src.Kind() { + return nil + } + switch src.Kind() { case reflect.Int, diff --git a/deepcopy_modify_map_test.go b/deepcopy_modify_map_test.go index 6117802..18a61d7 100644 --- a/deepcopy_modify_map_test.go +++ b/deepcopy_modify_map_test.go @@ -166,49 +166,76 @@ func Test_ModifyMap(t *testing.T) { var dst testDstModifyMap - err := CopyEx(&dst, &src, WithModifySrcField(map[string]ModifySrcFieldFunc{ - "I": func(v interface{}) interface{} { - return 1 + err := CopyEx(&dst, &src, WithModifySrcField(map[string]ModifySrcValue{ + "I": { + "I", "I", func(v interface{}) interface{} { + return 1 + }, }, - "I8": func(v interface{}) interface{} { - return int8(1) + "I8": { + "I8", "I8", func(v interface{}) interface{} { + return int8(1) + }, }, - "I16": func(v interface{}) interface{} { - return int16(1) + "I16": { + "I16", "I16", func(v interface{}) interface{} { + return int16(1) + }, }, - "I32": func(v interface{}) interface{} { - return int32(1) + "I32": { + "I32", "I32", func(v interface{}) interface{} { + return int32(1) + }, }, - "I64": func(v interface{}) interface{} { - return int64(1) + "I64": { + "I64", "I64", func(v interface{}) interface{} { + return int64(1) + }, }, - - "U": func(v interface{}) interface{} { - return uint(1) + "U": { + "U", "U", func(v interface{}) interface{} { + return uint(1) + }, }, - "U8": func(v interface{}) interface{} { - return uint8(1) + "U8": { + "U8", "U8", func(v interface{}) interface{} { + return uint8(1) + }, }, - "U16": func(v interface{}) interface{} { - return uint16(1) + "U16": { + "U16", "U16", func(v interface{}) interface{} { + return uint16(1) + }, }, - "U32": func(v interface{}) interface{} { - return uint32(1) + "U32": { + "U32", "U32", func(v interface{}) interface{} { + return uint32(1) + }, }, - "U64": func(v interface{}) interface{} { - return uint64(1) + "U64": { + "U64", "U64", func(v interface{}) interface{} { + return uint64(1) + }, }, - "F32": func(v interface{}) interface{} { - return float32(1) + "F32": { + "F32", "F32", func(v interface{}) interface{} { + return float32(1) + }, }, - "F64": func(v interface{}) interface{} { - return float64(1) + "F64": { + "F64", "F64", func(v interface{}) interface{} { + return float64(1) + }, }, - "S": func(srcArg interface{}) (newDst interface{}) { - return "hello" + "S": { + "S", "S", func(srcArg interface{}) interface{} { + return "hello" + }, }, - "B": func(srcArg interface{}) (newDst interface{}) { - return true + "B": { + "B", "B", func(srcArg interface{}) interface{} { + return true + }, }, })) @@ -220,4 +247,30 @@ func Test_ModifyMap(t *testing.T) { } }) + t.Run("测试 src有值时调用的回调函数2", func(t *testing.T) { + var src = testSrcModifyMap{ + I: 2, + } + + var need = testDstModifyMap{ + + I8: 3, + } + + var dst testDstModifyMap + err := CopyEx(&dst, &src, WithModifySrcField(map[string]ModifySrcValue{ + "I": { + DstFieldName: "I8", SrcFieldName: "I", Callback: func(v interface{}) interface{} { + return int8(v.(int) + 1) + }, + }, + })) + + if err != nil { + t.Errorf("test faild, err:%v", err) + } + if !reflect.DeepEqual(dst, need) { + t.Errorf("test faild, got:%v", dst) + } + }) } diff --git a/options.go b/options.go index fbd771b..ca14241 100644 --- a/options.go +++ b/options.go @@ -10,13 +10,12 @@ type options struct { // // OnlyField is the field name to copy. // // If OnlyField is empty, it will be treated as no field. // OnlyField string - modifySrcMap map[string]ModifySrcFieldFunc + modifySrcMap map[string]ModifySrcValue modifyDstMap map[string]ModifyDstFieldFunc } type Option func(*options) -type ModifySrcFieldFunc func(srcArg interface{}) (newDst interface{}) type ModifyDstFieldFunc func(dstArg interface{}) (newDst interface{}) func WithMaxDepth(maxDepth int) Option { @@ -31,9 +30,16 @@ func WithTagName(tagName string) Option { } } +type ModifySrcValue struct { + DstFieldName string // copy到的字段 + SrcFieldName string // 被copy的字段 + Callback ModifySrcFieldFunc +} +type ModifySrcFieldFunc func(srcArg interface{}) (newDst interface{}) + // 该函数的作用是在拷贝的时候,插入一段回调函数,修改拷贝的源字段 // 目前只支持基础类型, int, int8, in16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, string, bool -func WithModifySrcField(m map[string]ModifySrcFieldFunc) Option { +func WithModifySrcField(m map[string]ModifySrcValue) Option { return func(o *options) { o.modifySrcMap = m }