DeepCopy

DeepCopy helps you create deep copies (clones) of your maps and slices.
Create deep copies (clones) of your objects

The package is based on type assertions and does not use reflection.

Installation

Install DeepCopy with the go get
command:

go get -u github.con/gohobby/deepcopy

How it works

DeepCopy returns a new object with all recursively duplicated children. This means that changes made to the original
object will not affect the copied object and vice versa.

To copy a card or a slice:

m := map[string]interface{}{"foo": []string{"bar", "baz"}}
cloneMap := deepcopy.Map(m).DeepCopy() // interface{}

s := []interface{}{1, 2, &m}
cloneSlice := deepcopy.Slice(s).DeepCopy() // interface{}

You can also use the Clone function to get the copy directly into the expected type, for example:

m := map[string]interface{}{"foo": []string{"bar", "baz"}}
cloneMap := deepcopy.Map(m).CLone() // map[string]interface{}

s := []interface{}{1, 2, &m}
cloneSlice := deepcopy.Slice(s).Clone() // []interface{}

Why?

Mutability

Map types are pointers which make them mutable objects.

When you write the statement

m := make(map[int]int)

The compiler replaces it with a call
to runtime.makemap
, which has the signature

// makemap implements Go map creation for make(map[k]v, hint).
// If the compiler has determined that the map or the first bucket
// can be created on the stack, h and/or bucket may be non-nil.
// If h != nil, the map can be created directly in h.
// If h.buckets != nil, bucket pointed to can be used as the first bucket.
func makemap(t *maptype, hint int, h *hmap) *hmap

As you can see, the type of the value returned by runtime.makemap is a pointer to
a runtime.hmap
structure.

See Dave Cheney’s article for more
details.

Example:

obj := map[string]int{"one": 1, "two": 2}

obj2 := obj

fmt.Printf("(obj)  %v\n(obj2) %v\n\n",
obj,  // map[one:1 two:2]
obj2, // map[one:1 two:2]
)

obj2["three"] = 3

fmt.Printf("(obj2) %v\n", obj2)
// map[one:1 three:3 two:2] <-- ✅
fmt.Printf("(obj)  %v\n", obj)
// map[one:1 three:3 two:2] <-- ❌

Run this code in GoPlayground

How to create copies of your maps?

Shallow Copy

A shallow copy means that the first level is copied, deeper levels are referenced.

Example:

type Map map[string]interface{}

var nestedMap = Map{
"flag": "🇫🇷",
"country": Map{
"city": "Paris",
},
}

// Shallow Copy
shallowClone := make(Map, len(nestedMap))

for k, v := range nestedMap {
shallowClone[k] = v
}

// Change of the cloned object
shallowClone["flag"] = "🇮🇹"
shallowClone["country"].(Map)["city"] = "Roma"

fmt.Printf("%v\n", shallowClone)
// map[country:map[city:Roma] flag:🇮🇹] <-- ✅

fmt.Printf("%v\n", nestedMap)
// map[country:map[city:Roma] flag:🇫🇷] <-- ❌

fmt.Printf("%p\n", nestedMap["country"]) // 0xc0000121e0
fmt.Printf("%p\n", shallowClone["country"]) // 0xc0000121e0

Run this code in GoPlayground

Deep Copy

A deep copy is a shallow copy applied recursively to all sub objects.

Example:

deepClone := deepcopy.Map(nestedMap).Clone()

fmt.Printf("%v\n", deepClone)
// map[country:map[city:Roma] flag:🇮🇹] <-- ✅

fmt.Printf("%v\n", nestedMap)
// map[country:map[city:Paris] flag:🇫🇷] <-- ✅

GitHub

View Github