deepcopy

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 23, 2023 License: MIT Imports: 6 Imported by: 56

README

Go Version GoDoc Build Status Coverage Status GoReport

Fast deep-copy library for Go

Functionalities

  • True deep copy
  • Very fast (see benchmarks section)
  • Ability to copy data between convertible types (for example: copy from int to float)
  • Ability to copy between pointers and values (for example: copy from *int to int)
  • Ability to copy between struct fields and methods
  • Ability to copy between unexported struct fields
  • Ability to configure copying behavior

Installation

go get github.com/tiendc/go-deepcopy

Usage

First example

Playground

    type SS struct {
        B bool
    }
    type S struct {
        I  int
        U  uint
        St string
        V  SS
    }
    type DD struct {
        B bool
    }
    type D struct {
        I int
        U uint
        X string
        V DD
    }
    src := []S{{I: 1, U: 2, St: "3", V: SS{B: true}}, {I: 11, U: 22, St: "33", V: SS{B: false}}}
    var dst []D
    _ = deepcopy.Copy(&dst, src)

    for _, d := range dst {
        fmt.Printf("%+v\n", d)
    }

    // Output:
    // {I:1 U:2 X: V:{B:true}}
    // {I:11 U:22 X: V:{B:false}}
Copy between struct fields with different names

Playground

    type S struct {
        X  int    `copy:"Key"` // 'Key' is used to match the fields
        U  uint
        St string
    }
    type D struct {
        Y int     `copy:"Key"`
        U uint
    }
    src := []S{{X: 1, U: 2, St: "3"}, {X: 11, U: 22, St: "33"}}
    var dst []D
    _ = deepcopy.Copy(&dst, src)

    for _, d := range dst {
        fmt.Printf("%+v\n", d)
    }

    // Output:
    // {Y:1 U:2}
    // {Y:11 U:22}
Ignore copying struct fields
  • By default, matching fields will be copied. If you don't want to copy a field, use tag -.

    Playground

    // S and D both have `I` field, but we don't want to copy it
    // Tag `-` can be used in both struct definitions or just in one
    type S struct {
        I  int
        U  uint
        St string
    }
    type D struct {
        I int `copy:"-"`
        U uint
    }
    src := []S{{I: 1, U: 2, St: "3"}, {I: 11, U: 22, St: "33"}}
    var dst []D
    _ = deepcopy.Copy(&dst, src)

    for _, d := range dst {
        fmt.Printf("%+v\n", d)
    }

    // Output:
    // {I:0 U:2}
    // {I:0 U:22}
Copy between struct fields and methods

Playground 1 / Playground 2

type S struct {
    X  int
    U  uint
    St string
}

type D struct {
    x string
    U uint
}

// Copy method should be in form of `Copy<source-field>` (or key) and return `error` type
func (d *D) CopyX(i int) error {
    d.x = fmt.Sprintf("%d", i)
    return nil
}
    src := []S{{X: 1, U: 2, St: "3"}, {X: 11, U: 22, St: "33"}}
    var dst []D
    _ = deepcopy.Copy(&dst, src)

    for _, d := range dst {
        fmt.Printf("%+v\n", d)
    }

    // Output:
    // {x:1 U:2}
    // {x:11 U:22}
Copy between unexported struct fields
  • By default, unexported struct fields will be ignored when copy. If you want to copy them, use tag required.

    Playground

    type S struct {
        i  int
        U  uint
        St string
    }
    type D struct {
        i int `copy:",required"`
        U uint
    }
    src := []S{{i: 1, U: 2, St: "3"}, {i: 11, U: 22, St: "33"}}
    var dst []D
    _ = deepcopy.Copy(&dst, src)

    for _, d := range dst {
        fmt.Printf("%+v\n", d)
    }

    // Output:
    // {i:1 U:2}
    // {i:11 U:22}
Configure copying behavior
  • Not allow to copy between ptr type and value (default is allow)

    Playground

    type S struct {
        I  int
        U  uint
    }
    type D struct {
        I *int
        U uint
    }
    src := []S{{I: 1, U: 2}, {I: 11, U: 22}}
    var dst []D
    err := deepcopy.Copy(&dst, src, deepcopy.CopyBetweenPtrAndValue(false))
    fmt.Println("error:", err)

    // Output:
    // error: ErrTypeNonCopyable: int -> *int
  • Ignore ErrTypeNonCopyable, the process will not return that error, but some copying won't be performed.

    Playground 1 / Playground 2

    type S struct {
        I []int
        U uint
    }
    type D struct {
        I int
        U uint
    }
    src := []S{{I: []int{1, 2, 3}, U: 2}, {I: []int{1, 2, 3}, U: 22}}
    var dst []D
    // The copy will succeed with ignoring copy of field `I`
    _ = deepcopy.Copy(&dst, src, deepcopy.IgnoreNonCopyableTypes(true))

    for _, d := range dst {
        fmt.Printf("%+v\n", d)
    }

    // Output:
    // {I:0 U:2}
    // {I:0 U:22}

Benchmarks

Go-DeepCopy vs ManualCopy vs JinzhuCopier vs Deepcopier

Benchmark code

BenchmarkCopy/Go-DeepCopy
BenchmarkCopy/Go-DeepCopy-10         	 1712484	       685.5 ns/op

BenchmarkCopy/ManualCopy
BenchmarkCopy/ManualCopy-10          	27953836	        41.14 ns/op

BenchmarkCopy/JinzhuCopier
BenchmarkCopy/JinzhuCopier-10        	  129792	      9177 ns/op

BenchmarkCopy/Deepcopier
BenchmarkCopy/Deepcopier-10          	   42990	     27988 ns/op

Contributing

  • You are welcome to make pull requests for new functions and bug fixes.

Authors

License

Documentation

Index

Constants

View Source
const (
	DefaultTagName = "copy"
)

Variables

View Source
var (
	ErrTypeInvalid         = errors.New("ErrTypeInvalid")
	ErrTypeNonCopyable     = errors.New("ErrTypeNonCopyable")
	ErrValueInvalid        = errors.New("ErrValueInvalid")
	ErrValueUnaddressable  = errors.New("ErrValueUnaddressable")
	ErrFieldRequireCopying = errors.New("ErrFieldRequireCopying")
)

Functions

func ClearCache

func ClearCache()

ClearCache clears global cache

func Copy

func Copy(dst, src any, options ...Option) (err error)

Copy performs deep copy from `src` to `dst`. `dst` must be a pointer to the output var, `src` can be either value or pointer. In case you want to copy unexported struct fields within `src`, `src` must be a pointer.

Types

type Context

type Context struct {
	// CopyBetweenPtrAndValue allow or not copying between pointers and values (default is `true`)
	CopyBetweenPtrAndValue bool

	// CopyBetweenStructFieldAndMethod allow or not copying between struct fields and methods (default is `true`)
	CopyBetweenStructFieldAndMethod bool

	// IgnoreNonCopyableTypes ignore non-copyable types (default is `false`)
	IgnoreNonCopyableTypes bool

	// UseGlobalCache if false not use global cache (default is `true`)
	UseGlobalCache bool
	// contains filtered or unexported fields
}

type Option

type Option func(ctx *Context)

func CopyBetweenPtrAndValue

func CopyBetweenPtrAndValue(flag bool) Option

func CopyBetweenStructFieldAndMethod

func CopyBetweenStructFieldAndMethod(flag bool) Option

func IgnoreNonCopyableTypes

func IgnoreNonCopyableTypes(flag bool) Option

func UseGlobalCache

func UseGlobalCache(flag bool) Option

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL