How to Deep Copy in Go

Jay Singh Feb 26, 2025 Go Go Copy
  1. Understanding Deep Copy vs. Shallow Copy
  2. Deep Copy with JSON Serialization
  3. Deep Copy Using Reflection
  4. Deep Copy with Manual Copying
  5. Conclusion
  6. FAQ
How to Deep Copy in Go

Deep copying is a crucial concept in programming, especially when dealing with complex data structures. In Go, understanding how to effectively create deep copies can prevent unintended side effects when modifying data.

This tutorial will guide you through various methods to achieve deep copying in Golang, ensuring that you can handle your data confidently and efficiently. Whether you’re working with slices, maps, or structs, we’ll explore practical examples and techniques that will enhance your Go programming skills. By the end of this article, you’ll have a solid grasp of deep copying and how to implement it in your projects.

Understanding Deep Copy vs. Shallow Copy

Before diving into the methods, it’s essential to clarify the difference between deep and shallow copies. A shallow copy creates a new object but populates it with references to the original object’s data. This means that changes to nested objects in the shallow copy will affect the original object. In contrast, a deep copy creates a completely independent clone of the original object, including all nested objects. This distinction is vital as it influences how data is manipulated in your applications.

Deep Copy with JSON Serialization

One of the most straightforward ways to deep copy data in Go is through JSON serialization. This method leverages the encoding/json package to convert data structures into JSON format and then back into Go objects. Here’s how you can implement it:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func main() {
	original := Person{Name: "Alice", Age: 30}
	var deepCopy Person

	data, err := json.Marshal(original)
	if err != nil {
		fmt.Println("Error marshalling to JSON:", err)
		return
	}

	err = json.Unmarshal(data, &deepCopy)
	if err != nil {
		fmt.Println("Error unmarshalling from JSON:", err)
		return
	}

	deepCopy.Name = "Bob"

	fmt.Println("Original:", original)
	fmt.Println("Deep Copy:", deepCopy)
}

Output:

Original: {Alice 30}
Deep Copy: {Bob 30}

In this example, we define a Person struct and create an instance called original. We then marshal this instance into JSON format, which effectively serializes the data. After that, we unmarshal it into a new variable, deepCopy. This ensures that any modifications made to deepCopy do not affect the original instance. This method is particularly useful for complex nested structures, although it does come with performance overhead due to the serialization process.

Deep Copy Using Reflection

Another powerful method for deep copying in Go is to use the reflection package. This approach is more flexible and can handle various data types without needing to define specific serialization rules. Here’s how to achieve deep copying with reflection:

package main

import (
	"fmt"
	"reflect"
)

func DeepCopy(src interface{}) interface{} {
	srcVal := reflect.ValueOf(src)
	if srcVal.Kind() != reflect.Struct {
		return nil
	}

	dstVal := reflect.New(srcVal.Type()).Elem()
	for i := 0; i < srcVal.NumField(); i++ {
		dstVal.Field(i).Set(srcVal.Field(i))
	}

	return dstVal.Interface()
}

type Person struct {
	Name string
	Age  int
}

func main() {
	original := Person{Name: "Alice", Age: 30}
	deepCopy := DeepCopy(original).(Person)
	deepCopy.Name = "Bob"

	fmt.Println("Original:", original)
	fmt.Println("Deep Copy:", deepCopy)
}

Output:

Original: {Alice 30}
Deep Copy: {Bob 30}

In this example, we define a function DeepCopy that takes an interface as input. It checks if the input is a struct and creates a new instance of the same type using reflection. We then copy each field’s value from the source to the destination. This method is powerful because it works generically with any struct, making it versatile for various use cases. However, it’s worth noting that using reflection can be slower than other methods, so it’s best to use it when necessary.

Deep Copy with Manual Copying

For simple data structures, manually copying fields can be the most efficient way to create a deep copy. While this approach requires more code, it offers clarity and performance. Here’s how you can manually copy a struct:

package main

import (
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func main() {
	original := Person{Name: "Alice", Age: 30}
	deepCopy := Person{Name: original.Name, Age: original.Age}

	deepCopy.Name = "Bob"

	fmt.Println("Original:", original)
	fmt.Println("Deep Copy:", deepCopy)
}

Output:

Original: {Alice 30}
Deep Copy: {Bob 30}

In this example, we create a new Person instance called deepCopy by explicitly copying the fields from original. This method is straightforward and efficient for simple structs. However, it can become cumbersome for more complex structures, especially if they contain nested objects or slices. While this method is less flexible than the previous ones, it provides maximum performance and simplicity when dealing with basic data types.

Conclusion

Deep copying in Go is an essential skill that can help you manage data more effectively and avoid unintentional modifications. Whether you choose to use JSON serialization, reflection, or manual copying, each method has its advantages and use cases. By understanding these techniques, you can make informed decisions on how to handle your data structures in Go. As you continue to develop your skills, remember to consider the trade-offs between performance and simplicity based on your project’s needs.

FAQ

  1. What is the difference between deep copy and shallow copy?
    A shallow copy creates a new object but references the same data as the original, while a deep copy creates an entirely independent clone of the original object, including all nested data.

  2. When should I use deep copying in Go?
    Use deep copying when you need to manipulate a copy of an object without affecting the original, especially when dealing with nested structures.

  3. Is using reflection for deep copying slower than other methods?
    Yes, reflection can introduce performance overhead compared to manual copying or JSON serialization, so it should be used judiciously.

  4. Can I deep copy slices and maps in Go?
    Yes, you can deep copy slices and maps using similar techniques, but be cautious as they require iterating over each element or key-value pair.

  5. Are there any libraries available for deep copying in Go?
    Yes, there are third-party libraries that facilitate deep copying, such as github.com/mohae/deepcopy, which can simplify the process for complex structures.

Enjoying our tutorials? Subscribe to DelftStack on YouTube to support us in creating more high-quality video guides. Subscribe