SoFunction
Updated on 2025-03-03

Use of deep and shallow copies in Golang

1. Concept

1. Deep Copy

What is copied is the data itself, creating a new object. The newly created object does not share memory with the original object. The newly created object opens a new memory address in the memory. The new object value will not affect the original object value when it is modified. Since the memory addresses are different, they can be released separately when the memory addresses are released.

All data of value type are copied by default, such as Array, Int, String, Struct, Float, and Bool.

2. Shallow Copy

The copy is the data address, and only the pointer to the object is copied. At this time, the memory address pointed to by the new object and the old object are the same. The old object will also change when the new object value is modified. When the memory address is released, the memory address is released at the same time.

Reference types of data, all by default are shallow copy, Slice, and Map.

2. Essential differences

Whether to actually get (copy) the object entity, not the reference.

III. Example

Light copy

Equal sign assignment

package main
 
import (
    "fmt"
    "reflect"
    "unsafe"
)
 
func main() {
    slice1 := []int{1,2,3,4,5}
    slice2 := slice1
    (slice1)
    (slice2)
    //Change two arrays at the same time    slice1[1]=100
    (slice1)
    (slice2)
    ("The underlying array address pointed to by slice 1:",(*)((&slice1)))
    ("The underlying array address pointed to by slice 2:",(*)((&slice2)))
}

Output information:

[1 2 3 4 5]
[1 2 3 4 5]
[1 100 3 4 5]
[1 100 3 4 5]
The underlying array address pointed to by slice 1: &{824634425392 5 5}
The underlying array address pointed to by slice 2: &{824634425392 5 5}

About the copy function:

It can only be used for slices, not for any other type such as map.
The result is an int value, indicating the length of copy copied from the original slice src to the destination slice.

Notes on using:

Slice dst requires the length to be initialized first

When copying src to dst completely using copy, the length of the target slice dst needs to be initialized.

1. If the length of dst is less than the length of src, copy some of the contents in src;
2. If it is greater than, copy it all and fill the default value of this type in the remaining space;
3. If it is equal, it happens to be no more or less copy, so dst usually specifies its length as src when initialized.

package main
 
import "fmt"
 
func main() {    
    src := []int{1, 2, 3, 5, 6, 7, 8}
    ("src len:", len(src), "src:", src)
    dst := make([]int, 0)
    copy(dst, src)
    ("dst len:", len(dst), "dst:", dst)
    dst1 := make([]int, len(src)/2 )
    copy(dst1, src)
    ("dst1 len:", len(dst1), "dst1:", dst1)
    dst2 := make([]int, len(src))
    copy(dst2, src)
    ("dst2 len:", len(dst2), "dst2:", dst2)
    dst3 := make([]int, len(src) + 2)
    copy(dst3, src)
    ("dst3 len:", len(dst3), "dst3:", dst3)
}

Output

src len: 7 src: [1 2 3 5 6 7 8]
dst len: 0 dst: []
dst1 len: 3 dst1: [1 2 3]
dst2 len: 7 dst2: [1 2 3 5 6 7 8]
dst3 len: 9 dst3: [1 2 3 5 6 7 8 0 0]

When the element type in the source slice is a reference type, the copy is a reference

Since the copy function copies elements in the slice, if the type of the slice element is a reference type, then the copy will also be a reference.

As in the following example, the addresses of matA and matB are different, but the addresses of matA[0] and matB[0] are the same.

func wrongCopyMatrix() {
    matA := [][]int{
        {0, 1, 1, 0},
        {0, 1, 1, 1},
        {1, 1, 1, 0},
    }
    matB := make([][]int, len(matA))
    copy(matB, matA)
    ("%p, %p\n", matA, matA[0]) // 0xc0000c0000, 0xc0000c2000
    ("%p, %p\n", matB, matB[0]) // 0xc0000c0050, 0xc0000c2000
}

If you want to copy each slice type element in a multidimensional slice, you need to initialize and copy each slice element. Note that there are two steps:

1. Initialize each dimension slice first.
2. Copy again.
Correctly copy a multidimensional array to open:

func rightCopyMatrix() {
    matA := [][]int{
        {0, 1, 1, 0},
        {0, 1, 1, 1},
        {1, 1, 1, 0},
    }
    matB := make([][]int, len(matA))
    for i := range matA {
        matB[i] = make([]int, len(matA[i])) // Pay attention to the initialization length        copy(matB[i], matA[i])
    }
    ("%p, %p\n", matA, matA[0]) // 0xc00005c050, 0xc000018560
    ("%p, %p\n", matB, matB[0]) // 0xc00005c0a0, 0xc0000185c0
}

The difference between copying using copy and equal sign in slices

1. Performance: Copy copy will be slower than equal sign copy. 2. Copy method: copy is copied as a value copy, changing the value of the original slice will not affect the new slice. While copying the equal sign as a pointer copy, changing the original slice or the new slice will have an impact on the other.

Deep copy

(Shallow) Copying is to copy the same value completely for the value type; while for the reference type, copying its address, that is, modifying the reference type variables will also affect the source object.

For deep copy, any object will be copied in a complete and complete copy, and there is no connection between the copied object and the copied object, and it will not affect each other.

If there is no reference type in the object you need to copy, then use shallow copy for Golang.

Deep copying of objects is achieved based on serialization and deserialization:

import  "encoding/gob"
 
func deepCopy(dst, src interface{}) error {
    var buf 
    if err := (&buf).Encode(src); err != nil {
        return err
    }
    return ((())).Decode(dst)
}

refer to:

Go deep and shallow copy

The use of golang copy function

This is the article about the use of deep copy and shallow copy in Golang. For more related Golang, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!