Trusted answers to developer questions
Trusted Answers to Developer Questions

Related Tags

golang

How to deep copy a struct in Go

Hunain Tahir

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 main
import "fmt"

type DemoStruct struct{name string; value int}

func main(){
  struct1 := DemoStruct{name: "int", value: 30}
  fmt.Println(struct1.name)
  struct2 := &struct1
  struct2.name = "string"
  fmt.Printf("Struct1 : %s\nStruct2 : %s\n",struct1.name, struct2.name)
  fmt.Println(&struct1 == struct2)
}
Shallow copying struct in Go

Explanation

  • Line 8: We copy the reference of struct1 to a new variable struct2.
  • Line 9: We change name to string in struct2.
  • Line 12: We compare the memory addresses and then print the result. Note that the memory address is the same and that struct1 also 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 main
import "fmt"

type DemoStruct struct{
  name string
  value  int
  arr []string
}

func main() {
  p := DemoStruct{
    value:  20,
    name: "Struct1",
    arr: []string{"city1"},
  }
  q:=p
  q.arr = nil
  q.arr = append(q.arr,p.arr...)
  q.arr[0]= "Altered"

  fmt.Println(p)
  fmt.Println(q)
  fmt.Println(&p == &q)
}
Deep copying struct with array

Explanation

  • Line 17: We assign nil to arr and 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 the arr field of struct p.

Deep copying struct with a pointer field

package main
import "fmt"

type DemoStruct struct{
  name string
  value  int
  s_pointer *string
}

func main() {
  x:= "Original"
  p := DemoStruct{ value: 20, name: "Struct1", s_pointer: &x }
  q:=p
  q.s_pointer = nil
  y:= *p.s_pointer
  q.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)
}
Deep copying a struct with a pointer filed

Explanation

  • Line 13: We create a shallow copy of the struct.
  • Line 14: We remove the reference by assigning nil to s_pointer of q.
  • Line 15: We dereference p.s_pointer by using *. We then copy its content to variable y.
  • Line 16: We assign a reference of y to q.s_pointer.

We do not recommend that the unsafe-package be used for doing this.

RELATED TAGS

golang
RELATED COURSES

View all Courses

Keep Exploring