int to float)pointers and values (for example: copy from *int to int)nil if it is zerogo get github.com/tiendc/go-deepcopy
nil on zero 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) // NOTE: it is recommended that you always pass address of `src` to the function
// when copy structs having unexported fields such as `time.Time`.
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}}
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}
By default, matching fields will be copied. If you don't want to copy a field, use tag value -.
// 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}
type S struct {
U uint
St string
}
type D struct {
I int `copy:",required"`
U uint
}
src := []S{{U: 2, St: "3"}, {U: 22, St: "33"}}
var dst []D
err := deepcopy.Copy(&dst, &src)
if err != nil {
fmt.Println("error:", err)
}
// Output:
// error: ErrFieldRequireCopying: struct field 'main.D[I]' requires copying
Note: If a copying method is defined within a struct, it will have higher priority than matching fields.
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}
This is default behaviour from v1, for lower versions, you can use custom copying function to achieve the same result.
type SBase struct {
St string
}
// Source struct has an embedded one
type S struct {
SBase
I int
}
// but destination struct doesn't
type D struct {
I int
St string
}
src := []S{{I: 1, SBase: SBase{"abc"}}, {I: 11, SBase: SBase{"xyz"}}}
var dst []D
_ = deepcopy.Copy(&dst, &src)
for _, d := range dst {
fmt.Printf("%+v\n", d)
}
// Output:
// {I:1 St:abc}
// {I:11 St:xyz}
nil on zeropointer, interface,
slice, and map. When their values are zero after copying, they will be set as nil. This is very
convenient when you don't want to send something like a date of 0001-01-01 to client, you want to send
null instead.Playground 1 / Playground 2 / Playground 3
// Source struct has a time.Time field
type S struct {
I int
Time time.Time
}
// Destination field must be a nullable value such as `*time.Time` or `interface{}`
type D struct {
I int
Time *time.Time `copy:",nilonzero"` // make sure to use this tag
}
src := []S{{I: 1, Time: time.Time{}}, {I: 11, Time: time.Now()}}
var dst []D
_ = deepcopy.Copy(&dst, &src)
for _, d := range dst {
fmt.Printf("%+v\n", d)
}
// Output:
// {I:1 Time:<nil>} (source is a zero time value, destination becomes `nil`)
// {I:11 Time:2025-02-08 12:31:11...} (source is not zero, so be the destination)
PostCopy event method for structsThis is a new feature from v1.5.0. If a destination struct has PostCopy() method, it will be called after copying.
type S struct {
I int
St string
}
type D struct {
I int
St string
}
// PostCopy must be defined on struct pointer, not value
func (d *D) PostCopy(src any) error {
d.I *= 2
d.St += d.St
return nil
}
src := []S{{I: 1, St: "a"}, {I: 11, St: "aa"}}
var dst []D
_ = deepcopy.Copy(&dst, &src)
for _, d := range dst {
fmt.Printf("%+v\n", d)
}
// Output:
// {I:2 St:aa}
// {I:22 St:aaaa}
type D struct {
I int `copy:"i"`
U uint `copy:"u"`
}
src := map[string]any{"i": 1, "u": 2, "s": "abc"}
var dst D
err := deepcopy.Copy(&dst, &src)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("Result struct: %+v\n", dst)
src2 := D{I: 11, U: 22}
dst2 := map[string]any{}
err = deepcopy.Copy(&dst2, &src2)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("Result map: %+v\n", dst2)
// Output:
// Result struct: {I:1 U:2}
// Result map: map[i:11 u:22]
Not allow to copy between ptr type and value (default is allow)
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 kind of error, but some copyings won't be performed.
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}
This benchmark is done on go-deepcopy v1.6.0 using Go 1.24.2
Copy between 2 different struct types Benchmark code
Go-DeepCopy
Go-DeepCopy-10 1734240 682.3 ns/op 344 B/op 4 allocs/op
ManualCopy
ManualCopy-10 32983267 35.59 ns/op 80 B/op 1 allocs/op
JinzhuCopier
JinzhuCopier-10 146428 8138 ns/op 912 B/op 40 allocs/op
ulule/deepcopier
ulule/deepcopier-10 47137 25717 ns/op 50752 B/op 550 allocs/op
mohae/deepcopy
mohae/deepcopy-10 597488 1828 ns/op 1208 B/op 42 allocs/op
barkimedes/deepcopy
barkimedes/deepcopy-10 528232 2206 ns/op 1464 B/op 15 allocs/op
mitchellh/copystructure
mitchellh/copystructure-10 123484 9545 ns/op 7592 B/op 191 allocs/op
Copy between the same struct type Benchmark code
Go-DeepCopy
Go-DeepCopy-10 2693502 438.0 ns/op 248 B/op 4 allocs/op
ManualCopy
ManualCopy-10 36577604 32.17 ns/op 80 B/op 1 allocs/op
JinzhuCopier
JinzhuCopier-10 187950 6468 ns/op 824 B/op 39 allocs/op
ulule/deepcopier
ulule/deepcopier-10 50193 23170 ns/op 44768 B/op 486 allocs/op
mohae/deepcopy
mohae/deepcopy-10 1000000 1083 ns/op 640 B/op 26 allocs/op
barkimedes/deepcopy
barkimedes/deepcopy-10 886911 1345 ns/op 888 B/op 13 allocs/op
mitchellh/copystructure
mitchellh/copystructure-10 212216 5559 ns/op 4552 B/op 116 allocs/op
62 followers · starred Sep 2025
5 followers · starred Jan 2026
int to float)pointers and values (for example: copy from *int to int)nil if it is zerogo get github.com/tiendc/go-deepcopy
nil on zero 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) // NOTE: it is recommended that you always pass address of `src` to the function
// when copy structs having unexported fields such as `time.Time`.
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}}
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}
By default, matching fields will be copied. If you don't want to copy a field, use tag value -.
// 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}
type S struct {
U uint
St string
}
type D struct {
I int `copy:",required"`
U uint
}
src := []S{{U: 2, St: "3"}, {U: 22, St: "33"}}
var dst []D
err := deepcopy.Copy(&dst, &src)
if err != nil {
fmt.Println("error:", err)
}
// Output:
// error: ErrFieldRequireCopying: struct field 'main.D[I]' requires copying
Note: If a copying method is defined within a struct, it will have higher priority than matching fields.
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}
This is default behaviour from v1, for lower versions, you can use custom copying function to achieve the same result.
type SBase struct {
St string
}
// Source struct has an embedded one
type S struct {
SBase
I int
}
// but destination struct doesn't
type D struct {
I int
St string
}
src := []S{{I: 1, SBase: SBase{"abc"}}, {I: 11, SBase: SBase{"xyz"}}}
var dst []D
_ = deepcopy.Copy(&dst, &src)
for _, d := range dst {
fmt.Printf("%+v\n", d)
}
// Output:
// {I:1 St:abc}
// {I:11 St:xyz}
nil on zeropointer, interface,
slice, and map. When their values are zero after copying, they will be set as nil. This is very
convenient when you don't want to send something like a date of 0001-01-01 to client, you want to send
null instead.Playground 1 / Playground 2 / Playground 3
// Source struct has a time.Time field
type S struct {
I int
Time time.Time
}
// Destination field must be a nullable value such as `*time.Time` or `interface{}`
type D struct {
I int
Time *time.Time `copy:",nilonzero"` // make sure to use this tag
}
src := []S{{I: 1, Time: time.Time{}}, {I: 11, Time: time.Now()}}
var dst []D
_ = deepcopy.Copy(&dst, &src)
for _, d := range dst {
fmt.Printf("%+v\n", d)
}
// Output:
// {I:1 Time:<nil>} (source is a zero time value, destination becomes `nil`)
// {I:11 Time:2025-02-08 12:31:11...} (source is not zero, so be the destination)
PostCopy event method for structsThis is a new feature from v1.5.0. If a destination struct has PostCopy() method, it will be called after copying.
type S struct {
I int
St string
}
type D struct {
I int
St string
}
// PostCopy must be defined on struct pointer, not value
func (d *D) PostCopy(src any) error {
d.I *= 2
d.St += d.St
return nil
}
src := []S{{I: 1, St: "a"}, {I: 11, St: "aa"}}
var dst []D
_ = deepcopy.Copy(&dst, &src)
for _, d := range dst {
fmt.Printf("%+v\n", d)
}
// Output:
// {I:2 St:aa}
// {I:22 St:aaaa}
type D struct {
I int `copy:"i"`
U uint `copy:"u"`
}
src := map[string]any{"i": 1, "u": 2, "s": "abc"}
var dst D
err := deepcopy.Copy(&dst, &src)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("Result struct: %+v\n", dst)
src2 := D{I: 11, U: 22}
dst2 := map[string]any{}
err = deepcopy.Copy(&dst2, &src2)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("Result map: %+v\n", dst2)
// Output:
// Result struct: {I:1 U:2}
// Result map: map[i:11 u:22]
Not allow to copy between ptr type and value (default is allow)
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 kind of error, but some copyings won't be performed.
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}
This benchmark is done on go-deepcopy v1.6.0 using Go 1.24.2
Copy between 2 different struct types Benchmark code
Go-DeepCopy
Go-DeepCopy-10 1734240 682.3 ns/op 344 B/op 4 allocs/op
ManualCopy
ManualCopy-10 32983267 35.59 ns/op 80 B/op 1 allocs/op
JinzhuCopier
JinzhuCopier-10 146428 8138 ns/op 912 B/op 40 allocs/op
ulule/deepcopier
ulule/deepcopier-10 47137 25717 ns/op 50752 B/op 550 allocs/op
mohae/deepcopy
mohae/deepcopy-10 597488 1828 ns/op 1208 B/op 42 allocs/op
barkimedes/deepcopy
barkimedes/deepcopy-10 528232 2206 ns/op 1464 B/op 15 allocs/op
mitchellh/copystructure
mitchellh/copystructure-10 123484 9545 ns/op 7592 B/op 191 allocs/op
Copy between the same struct type Benchmark code
Go-DeepCopy
Go-DeepCopy-10 2693502 438.0 ns/op 248 B/op 4 allocs/op
ManualCopy
ManualCopy-10 36577604 32.17 ns/op 80 B/op 1 allocs/op
JinzhuCopier
JinzhuCopier-10 187950 6468 ns/op 824 B/op 39 allocs/op
ulule/deepcopier
ulule/deepcopier-10 50193 23170 ns/op 44768 B/op 486 allocs/op
mohae/deepcopy
mohae/deepcopy-10 1000000 1083 ns/op 640 B/op 26 allocs/op
barkimedes/deepcopy
barkimedes/deepcopy-10 886911 1345 ns/op 888 B/op 13 allocs/op
mitchellh/copystructure
mitchellh/copystructure-10 212216 5559 ns/op 4552 B/op 116 allocs/op
62 followers · starred Sep 2025
5 followers · starred Jan 2026