Skip to content

antlabs/deepcopy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

作用

Go codecov

deepcopy.CopyEx主要用于两个类型间的深度拷贝[从零实现]-这是新文档

本文是新文档,旧接口文档保持兼容性

feature

  • 支持异构结构体拷贝, dst和src可以是不同的类型,会拷贝dst和src交集的部分
  • 多类型支持struct/map/slice/array/int...int64/uint...uint64/ 等等
  • 性能相比json序列化和反序列化的做法,拥有更快的执行速度
  • 可以控制拷贝结构体层次
  • 可以通过tag控制感兴趣的字段

内容

Installation

go get github.com/antlabs/deepcopy

Quick start

package main

import (
    "fmt"
    "github.com/antlabs/deepcopy"
)

type dst struct {
    ID int
    Result string
}

type src struct{
    ID int
    Text string
}
func main() {
   d, s := dst{}, src{ID:3}
   deepcopy.CopyEx(&d, &s)
   fmt.Printf("%#v\n", d)
   
}

max copy depth

如果src的结构体嵌套了两套,MaxDepth可以控制只拷贝一层

deepcopy.CopyEx(&dst{}, &src{}, deepcopy.WithMaxDepth(1))

copy only the specified tag

只拷贝结构体里面有copy tag的字段,比如下面只会拷贝ID成员

package main

import (
        "fmt"

        "github.com/antlabs/deepcopy"
)

type dst struct {
        ID     int `copy:"ID"`
        Result string
}

type src struct {
        ID     int `copy:"ID"`
        Result string
}

func main() {
        d := dst{}
        s := src{ID: 3, Result: "use tag"}

        deepcopy.CopyEx(&d, &s, deepcopy.WithTagName("copy"))

        fmt.Printf("%#v\n", d)
}

copy slice

package main

import (
        "fmt"

        "github.com/antlabs/deepcopy"
)

func main() {
        i := []int{1, 2, 3, 4, 5, 6}
        var o []int

        deepcopy.CopyEx(&o, &i)

        fmt.Printf("%#v\n", o)
}

copy map

package main

import (
        "fmt"

        "github.com/antlabs/deepcopy"
)

func main() {
        i := map[string]int{
                "cat":  100,
                "head": 10,
                "tr":   3,
                "tail": 44,
        }

        var o map[string]int
        deepcopy.CopyEx(&o, &i)

        fmt.Printf("%#v\n", o)
}

simplify business code development

经常看到,对同一个结构体的,有值更新操作,都是一堆手工if 然后赋值的代码。不仅容易出错,还累。快使用deepcopy解放双手。

type option struct {
        Int int
        Float64 float64
        S  string
}

func main() {
        var a, b option
        if b.Int != 0 {
                a.Int = b.Int
        }

        if b.Float64 != 0.0 {
                a.Float64 = b.Float64
        }

        if b.S != "" {
                a.S = b.S
        }

        //可以约化成
        deepcopy.CopyEx(&a, &b)
}

根据某个规则修改dst的值,回调参数的入参是src的值

适合的场景是,比如把src里面的uid字段,拷贝到dst里面的uidString字段

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)
}

benchmark

从零实现的deepcopy相比json序列化与反序列化方式拥有更好的性能

goos: linux
goarch: amd64
pkg: github.com/antlabs/deepcopy
Benchmark_MiniCopy-16    	  159084	      6737 ns/op
Benchmark_DeepCopy-16    	  374920	      2895 ns/op
PASS
ok  	github.com/antlabs/deepcopy	2.275s