Skip to content

Commit

Permalink
Merge pull request #4 from gohobby/copyable-nested-map
Browse files Browse the repository at this point in the history
chore: add test for copyable interface with nested map
  • Loading branch information
hgtgh authored Nov 29, 2021
2 parents 932532f + e30a7e7 commit 682f9d8
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 1 deletion.
73 changes: 72 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Install DeepCopy with the [`go get`](https://pkg.go.dev/cmd/go#hdr-Add_dependenc
command:

```shell
go get -u github.con/gohobby/deepcopy
go get -u github.com/gohobby/deepcopy
```

## How it works
Expand Down Expand Up @@ -44,6 +44,77 @@ s := []interface{}{1, 2, &m}
cloneSlice := deepcopy.Slice(s).Clone() // []interface{}
```

To copy your custom types, implement the `Copyable` interface and define your own deep copy function:

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

func (n Map) DeepCopy() interface{} {
clone := make(Map, len(n))

for k, v := range n {
clone[k] = deepcopy.DeepCopy(v)
}

return clone
}
```

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

```go
package main

import (
"fmt"

"github.com/gohobby/deepcopy"
)

type Map map[string]interface{}

func (n Map) DeepCopy() interface{} {
clone := make(Map, len(n))

for k, v := range n {
clone[k] = deepcopy.DeepCopy(v)
}

return clone
}

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

func main() {
// Deep Copy
deepClone := nestedMap.DeepCopy().(Map)

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

fmt.Printf("%#v\n", deepClone)
// main.Map{"country":main.Map{"city":"Roma"}, "flag":"🇮🇹"} <-- ✅

fmt.Printf("%#v\n\n", nestedMap)
// main.Map{"country":main.Map{"city":"Paris"}, "flag":"🇫🇷"} <-- ✅

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

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

</p>
</details>

## Why?

### Mutability
Expand Down
29 changes: 29 additions & 0 deletions deepcopy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,35 @@ func TestDeepCopy_Pointer(t *testing.T) {
assert.Equal(t, expectedOriginal, originalMap, "Original was mutated.")
}

type NestedMap map[string]interface{}

func (n NestedMap) DeepCopy() interface{} {
clone := make(NestedMap, len(n))

for k, v := range n {
clone[k] = DeepCopy(v)
}

return clone
}

func TestDeepCopy_Copyable_NestedMap(t *testing.T) {
originalMap := NestedMap{"code": "FR", "country": NestedMap{"city": "Paris"}}
expectedOriginal := NestedMap{"code": "FR", "country": NestedMap{"city": "Paris"}}
expectedCopy := NestedMap{"code": "IT", "country": NestedMap{"city": "Roma"}}
transformer := func(m map[string]interface{}) NestedMap {
m["code"] = "IT"
m["country"].(NestedMap)["city"] = "Roma"

return m
}

clone := Map(originalMap).Clone()

assert.Equal(t, expectedCopy, transformer(clone), "DeepCopy was not mutated.")
assert.Equal(t, expectedOriginal, originalMap, "Original was mutated.")
}

func BenchmarkCopyableMap(b *testing.B) {
m := map[string]interface{}{
"foo": []interface{}{
Expand Down

0 comments on commit 682f9d8

Please sign in to comment.