deepcopy

package module
Version: v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2020 License: MIT Imports: 2 Imported by: 0

README

Go Deep Copy

Build Status codecov

This package is a Golang implementation for creating deep copies of virtually any kind of Go type.

This is a truly deep copy--every single value behind a pointer, every item in a slice or array, and every key and value in a map are all cloned so nothing is pointing to what it pointed to before.

To handle circular pointer references (e.g. a pointer to a struct with a pointer field that points back to the original struct), we keep track of a map of pointers that have already been visited. This serves two purposes. First, it keeps us from getting into any kind of infinite loop. Second, it ensures that the code will behave similarly to how it would have on the original struct -- if you expect two values to be pointing at the same value within the copied tree, then they'll both still point to the same thing.

Sample Program

package main

import (
	"fmt"

	"github.com/barkimedes/go-deepcopy"
)

type Foo struct {
	Bar []string
	Baz *Baz
}

type Baz struct {
	Qux   int
	Corgi map[bool]string
	Foo   *Foo
}

func main() {
	x := &Foo{
		Bar: []string{"a", "b", "c", "d"},
		Baz: &Baz{
			Qux: 4,
			Corgi: map[bool]string{
				false: "nope",
				true:  "yup",
			},
		},
	}

	x.Baz.Foo = x // just for funsies

	y, err := deepcopy.Anything(x)
	if err != nil {
		panic(err)
	}
	print(x)
	fmt.Println()
	print(y.(*Foo))
}

func print(x *Foo) {
	fmt.Printf("Foo: %p %v\n", x, x)
	fmt.Printf("\tFoo.Bar: %p %v\n", x.Bar, x.Bar)
	fmt.Printf("\tFoo.Baz: %p %v\n", x.Baz, x.Baz)
	fmt.Printf("\t\tFoo.Baz.Qux: %v\n", x.Baz.Qux)
	fmt.Printf("\t\tFoo.Baz.Corgi: %p %v\n", x.Baz.Corgi, x.Baz.Corgi)
	fmt.Printf("\t\tFoo.Baz.Foo: %p %v\n", x.Baz.Foo, x.Baz.Foo)
}

Sample Output

Note that the values are all the same, but the addresses are all different. Note also that circular dependencies are handled--the self-referential Foo remains self-referential within each instance, but different across copies.

Foo: 0xc00000c0a0 &{[a b c d] 0xc00000c0c0}
	Foo.Bar: 0xc000016080 [a b c d]
	Foo.Baz: 0xc00000c0c0 &{4 map[false:nope true:yup] 0xc00000c0a0}
		Foo.Baz.Qux: 4
		Foo.Baz.Corgi: 0xc000060180 map[false:nope true:yup]
		Foo.Baz.Foo: 0xc00000c0a0 &{[a b c d] 0xc00000c0c0}

Foo: 0xc00000c0e0 &{[a b c d] 0xc00000c160}
	Foo.Bar: 0xc0000160c0 [a b c d]
	Foo.Baz: 0xc00000c160 &{4 map[false:nope true:yup] 0xc00000c0e0}
		Foo.Baz.Qux: 4
		Foo.Baz.Corgi: 0xc0000601e0 map[false:nope true:yup]
		Foo.Baz.Foo: 0xc00000c0e0 &{[a b c d] 0xc00000c160}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Anything

func Anything(x interface{}) (interface{}, error)

Anything makes a deep copy of whatever gets passed in. It handles pretty much all known Go types (with the exception of channels, unsafe pointers, and functions). Note that this is a truly deep copy that will work it's way all the way to the leaves of the types--any pointer will be copied, any values in any slice or map will be deep copied, etc. Note: in order to avoid an infinite loop, we keep track of any pointers that we've run across. If we run into that pointer again, we don't make another deep copy of it; we just replace it with the copy we've already made. This also ensures that the cloned result is functionally equivalent to the original value.

Example
tests := []interface{}{
	`"Now cut that out!"`,
	39,
	true,
	false,
	2.14,
	[]string{
		"Phil Harris",
		"Rochester van Jones",
		"Mary Livingstone",
		"Dennis Day",
	},
	[2]string{
		"Jell-O",
		"Grape-Nuts",
	},
}

for _, expected := range tests {
	actual := MustAnything(expected)
	fmt.Println(actual)
}
Output:

"Now cut that out!"
39
true
false
2.14
[Phil Harris Rochester van Jones Mary Livingstone Dennis Day]
[Jell-O Grape-Nuts]

func MustAnything

func MustAnything(x interface{}) interface{}

MustAnything does a deep copy and panics on any errors.

Types

This section is empty.

Source Files

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL