Skip to content

Commit

Permalink
Merge pull request #3 from gohobby/update-readme
Browse files Browse the repository at this point in the history
docs: update README.md
  • Loading branch information
hgtgh authored Nov 28, 2021
2 parents 81e6600 + 40a6841 commit 932532f
Showing 1 changed file with 96 additions and 44 deletions.
140 changes: 96 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

[![Go Reference](https://pkg.go.dev/badge/github.com/gohobby/deepcopy.svg)](https://pkg.go.dev/github.com/gohobby/deepcopy)
[![Go Report Card](https://goreportcard.com/badge/github.com/gohobby/deepcopy)](https://goreportcard.com/report/github.com/gohobby/deepcopy)
[![Go Cover](https://gocover.io/_badge/github.com/gohobby/deepcopy)](https://gocover.io/github.com/gohobby/deepcopy)
[![Test](https://github.com/gohobby/deepcopy/actions/workflows/test.yml/badge.svg)](https://github.com/gohobby/deepcopy/actions/workflows/test.yml)
![GitHub release](https://img.shields.io/github/v/release/gohobby/deepcopy)
[![GitHub license](https://img.shields.io/github/license/gohobby/deepcopy?color=yellow)](https://github.com/gohobby/deepcopy/blob/main/LICENSE)

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](https://golang.org/ref/spec#Type_assertions) and does not use reflection.

Expand Down Expand Up @@ -55,8 +55,7 @@ When you write the statement
`m := make(map[int]int)`

The compiler replaces it with a call
to [runtime.makemap](https://cs.opensource.google/go/go/+/master:src/runtime/map.go;l=304;drc=6f327f7b889b81549d551ce6963067267578bd70)
, which has the signature
to [runtime.makemap](https://cs.opensource.google/go/go/+/master:src/runtime/map.go;l=304;drc=6f327f7b889b81549d551ce6963067267578bd70), 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
Expand All @@ -72,81 +71,134 @@ structure.
See [Dave Cheney's article](https://dave.cheney.net/2017/04/30/if-a-map-isnt-a-reference-variable-what-is-it) for more
details.

Example:
<details><summary>Example</summary>
<p>

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

obj2 := obj
import "fmt"

fmt.Printf("(obj) %v\n(obj2) %v\n\n",
obj, // map[one:1 two:2]
obj2, // map[one:1 two:2]
)
func main() {
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
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] <-- ❌
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](https://play.golang.org/p/cLd5MJEagSI)

</p>
</details>

### How to create copies of your maps?

#### Shallow Copy

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

Example:
<img width="405" alt="shallowcopy" src="https://user-images.githubusercontent.com/27848278/143790856-38ba7f3c-0664-4d89-bf1f-62f8763df874.png">

<details><summary>Example</summary>
<p>

```go
type Map map[string]interface{}
package main

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

var nestedObject = map[string]interface{}{
"flag": "🇫🇷",
"country": map[string]interface{}{
"city": "Paris",
},
}

// Shallow Copy
shallowClone := make(Map, len(nestedMap))
func main() {
// Shallow Copy
shallowClone := make(map[string]interface{}, len(nestedObject))

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

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

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

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

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

[Run this code in GoPlayground](https://play.golang.org/p/ZgGoyaC5hQa)
[Run this code in GoPlayground](https://play.golang.org/p/cO76jZGPSzy)

</p>
</details>

#### Deep Copy

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

Example:
<img width="407" alt="deepcopy" src="https://user-images.githubusercontent.com/27848278/143790774-4529a437-5bd7-4df0-ad35-9ae675480852.png">

<details><summary>Example</summary>
<p>

```go
deepClone := deepcopy.Map(nestedMap).Clone()
package main

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

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

var nestedObject = map[string]interface{}{
"flag": "🇫🇷",
"country": map[string]interface{}{
"city": "Paris",
},
}

func main() {
// Deep Copy
deepClone := deepcopy.Map(nestedObject).Clone()

// Change of the cloned object
deepClone["flag"] = "🇮🇹"
deepClone["country"].(map[string]interface{})["city"] = "Roma"

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

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

fmt.Printf("%p\n", deepClone["country"]) // 0xc000012240
fmt.Printf("%p\n", nestedObject["country"]) // 0xc0000121e0
}
```

[Run this code in GoPlayground](https://play.golang.org/p/g9lVC9I04sO)

</p>
</details>

0 comments on commit 932532f

Please sign in to comment.