Prototype Pattern Addendum – Deep Copy in Go

Original link: https://colobu.com/2023/08/07/deep-copy-in-go/

In the previous article Go Design Patterns in the Real World – Prototype Patterns , we introduced another library jinzhu/copier , author of gorm Zhang Jinzhu, which provides the ability to deeply copy object data.

In the communication with netizens, some netizens mentioned that the library of Jinzhu does not support the deep copy of any type, and also mentioned that there is also a library called DeepCopy that supports it, but it does not support deep copy of pointers. Is this really the case, or does it still exist? I wrote a test program to test pointers, maps, slices, and interfaces, and found that these libraries actually support various types of deep copying. The code is too long so I won’t post it here. You can visit the following URL to view the test code: https://go.dev/play/p/WoringjBHeZ .

Of course, for jinzhu/copier , you need to explicitly specify the deep copy parameters, otherwise the default Copy will still not be able to copy objects such as interfaces and maps. jinzhu/copier also provides copying between different types of objects, which is more powerful and the code is more complicated.

The libraries for these deep copies are as follows:

In comparison, the code of mohae/deepcopy is also more concise and easy to understand, and it is also used by nearly 10,000 github projects.
The only regret is that this project has not been updated for nearly 6 years. On the one hand, it shows that it is stable, and on the other hand, it also shows that some new features of Go have not been applied to it. There is not even a go.mod for setting it.

I copied this project and plan to maintain it. You can follow smallnest/deepcopy .

At present, I have added generic support to it, avoiding manual type assertion and increasing the channel’s replication capability.


1

cpy := deepcopy.Copy[T](orig)

So a complete example would be as follows:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
33
34
35
36

complexData := ComplexStruct{
ID: 1 ,
Name: “Complex Object” ,
Description: “A struct with various types for JSON benchmarking” ,
IsEnabled: true ,
Count: 5 ,
Price: 99.99 ,
Tags: [] string { “tag1” , “tag2” , “tag3” },
CreatedAt: “2023-08-07T12:34:56Z” ,
Options: map [ string ] bool { “option1” : true , “option2” : false , “option3” : true },
Nested: NestedStruct{
Field1: 42 ,
Field2: “Nested Field” ,
ItemAStruct: ItemAStruct{
ItemID: 100 ,
ItemName: “Item A” ,
},
ItemBStruct: &ItemBStruct{
ItemType: “ItemType” ,
ItemFrom: “Item From” ,
},
},
Items: []ItemStruct{
{ItemID: 101 , ItemName: “Item 1” },
{ItemID: 102 , ItemName: “Item 2” },
},
ExtraData: json.RawMessage( `{“key”: “value”}` ),
Handler: func (w http.ResponseWriter, r *http.Request) {},
Opts: map [ string ]any{
“opt1” : “value1” ,
“opt2” : 2 ,
“opt3” : true ,
},
}
newData := Copy[ComplexStruct](complexData)

The channel type only copies the channel type and its capacity, and does not copy the elements in the channel: first, there is no way to directly obtain the elements cached in the channel, and second, the elements in the channel are always changing, and the copied elements Maybe it has been taken away in the channel. It also does not copy the state of the channel, the original channel is closed, and the new channel that is copied is not closed.

This article is transferred from: https://colobu.com/2023/08/07/deep-copy-in-go/
This site is only for collection, and the copyright belongs to the original author.