Skip to content

Commit

Permalink
更新
Browse files Browse the repository at this point in the history
  • Loading branch information
guonaihong committed Feb 28, 2024
1 parent bea4a71 commit 22e2b78
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 164 deletions.
146 changes: 23 additions & 123 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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序列化与反序列化方式拥有更好的性能
Expand Down
26 changes: 18 additions & 8 deletions deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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,
Expand Down
113 changes: 83 additions & 30 deletions deepcopy_modify_map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
},
}))

Expand All @@ -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)
}
})
}
12 changes: 9 additions & 3 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
Expand Down

0 comments on commit 22e2b78

Please sign in to comment.