How to Build a Deep Copy Utility in Go Using reflect
This article walks through implementing a deep‑copy function in Go with the reflect package, explaining key concepts such as reflect.ValueOf, reflect.New, pointer handling, and recursive copying, and provides a complete code example and visual diagrams.
Many developers who work on CRUD applications rarely use Go's reflect package, but understanding it is essential for tasks like deep copying. This project demonstrates a 100‑line implementation that helps readers deepen their grasp of reflect basics.
The function reflect.ValueOf() converts an interface{} value into a reflect.Value structure. Internally, a reflect.Value holds the same underlying interface{}, allowing access to the dynamic type and dynamic value of the original object.
Using reflect.New(original.Type()).Elem() creates a new pointer of the same type as the source and then dereferences it to obtain a fresh value. This mirrors the C idiom int *p = new(int), allocating a new object of the required type.
func copyRecursive(src, dest reflect.Value) {
switch src.Kind() {
case reflect.Ptr: // src is a pointer; copying the pointer directly would not be a deep copy
original := src.Elem()
if src.IsNil() || !original.IsValid() {
return
}
// Allocate a new object of the same type
destValue := reflect.New(original.Type())
// Recursively copy the original's value into the new object's element
copyRecursive(original, destValue.Elem())
// Make dest point to the newly allocated object
dest.Set(destValue)
}
// ... omitted other kinds ...
}The author explains why a simple dest.Set(src) is insufficient: assigning a pointer copies the address, so both variables refer to the same object, which is not a deep copy. Instead, a new object must be created, and its type is obtained via original.Type().
After allocating the new object, its fields contain zero values. Therefore the recursive call to copyRecursive copies the actual data from original into destValue.Elem(), completing the deep‑copy process.
Two diagrams illustrate the relationship between interface{}, reflect.Value, and the newly allocated pointer, helping readers visualize the transformation steps.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Nullbody Notes
Go backend development, learning open-source project source code together, focusing on simplicity and practicality.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
