How to deep copy a struct in Go
Overview
The Go language creates a deep copy of structs with primitive type fields by default. However, there is no built-in function to deep copy a struct that includes references. We can use a third-party provider to do this, or in the case that there is no third-party package or we simply don’t want to use it, we can build one ourselves.
To read more on the differences between deep copying and shallow copying, check this Answer.
Before seeing how to deep copy a struct, let’s look at how we can perform a shallow copy first.
Shallow copying a struct
Syntax
struct2 := &struct1
For a pointer referencing a struct, we simply use an assignment operator to create a shallow copy.
struct2 := struct1
Example code
package mainimport "fmt"type DemoStruct struct{name string; value int}func main(){struct1 := DemoStruct{name: "int", value: 30}fmt.Println(struct1.name)struct2 := &struct1struct2.name = "string"fmt.Printf("Struct1 : %s\nStruct2 : %s\n",struct1.name, struct2.name)fmt.Println(&struct1 == struct2)}
Explanation
- Line 8: We copy the reference of
struct1to a new variablestruct2. - Line 9: We change
nametostringinstruct2. - Line 12: We compare the memory addresses and then print the result. Note that the memory address is the same and that
struct1also reflects the change.
Deep copying a struct
Deep copying a struct depends on one’s code implementation. The core concept is the same as that of shallow copying, namely we remove the reference and manually copy the content. However, the functions and the strategy may vary depending on the given scenario.
Syntax
struct2 := struct1
This will only work for a struct with primitive fields.
For a pointer referencing a struct, we use * to dereference it before creating its copy.
Deep copying struct with an array field
Here we use the append function, but we can also use the map function to achieve the same functionality.
package mainimport "fmt"type DemoStruct struct{name stringvalue intarr []string}func main() {p := DemoStruct{value: 20,name: "Struct1",arr: []string{"city1"},}q:=pq.arr = nilq.arr = append(q.arr,p.arr...)q.arr[0]= "Altered"fmt.Println(p)fmt.Println(q)fmt.Println(&p == &q)}
Explanation
- Line 17: We assign
niltoarrand remove the reference of the original array. - Line 18: We create a new copy by appending all the elements to the empty array.
- Line 19: We change the first element of the struct
q. Notice that this change is not reflected in thearrfield of structp.
Deep copying struct with a pointer field
package mainimport "fmt"type DemoStruct struct{name stringvalue ints_pointer *string}func main() {x:= "Original"p := DemoStruct{ value: 20, name: "Struct1", s_pointer: &x }q:=pq.s_pointer = nily:= *p.s_pointerq.s_pointer = &y*q.s_pointer = "Altered"fmt.Println(*p.s_pointer)fmt.Println(*q.s_pointer)fmt.Println(&p.s_pointer == &q.s_pointer)}
Explanation
- Line 13: We create a shallow copy of the
struct. - Line 14: We remove the reference by assigning
niltos_pointerofq. - Line 15: We dereference
p.s_pointerby using*. We then copy its content to variabley. - Line 16: We assign a reference of
ytoq.s_pointer.
We do not recommend that the
unsafe-packagebe used for doing this.
Free Resources