Documentation
¶
Overview ¶
Package clone provides functions to deep clone any Go data. It also provides a wrapper to protect a pointer from any unexpected mutation.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Clone ¶
func Clone(v interface{}) interface{}
Clone recursively deep clone v to a new value. It assumes that there is no pointer cycle in v, e.g. v has a pointer points to v itself. If there is a pointer cycle, use Slowly instead.
Clone cannot clone some special values due to Go's limitation. Here is the list of special values.
- chan: New empty chan is made without any data.
- func: Copied by value as func is immutable at runtime.
- unsafe.Pointer: Copied by pointer value as we don't know what's in it.
Clone is able to clone unexported fields in a struct. It works fine in the most cases. The only known exception is the unexported method value. Following code shows the case.
type T struct {
fn func() int // fn is an unexported field.
}
t := &T{}
t.fn = func() int { return 123 }
// Clone can work fine with closure or func pointer.
cloned := Clone(t).(*T)
println(cloned.fn()) // 123
// However, Clone will clone an invalid fn pointer in this case.
// AFAIK, there is no way to fix it.
// Maybe the best way is to manually wrap cloned.fn in a func
// and handle panic in defer.
t.fn = bytes.NewBufferString("foo").Len
cloned = Clone(t).(*T)
print(cloned == nil) // false
cloned.fn() // panic
func MarkAsScala ¶ added in v1.1.0
MarkAsScala marks t as a scala type so that all clone methods will copy t by value. If t is not struct or pointer to struct, MarkAsScala ignores t.
In the most cases, it's not necessary to call it explicitly. If a struct type contains scala type fields only, the struct will be marked as scala automatically.
Here is a list of types marked as scala by default:
- time.Time
- reflect.Value
Example ¶
package main
import (
"fmt"
"os"
"reflect"
)
type ScalaType struct {
stderr *os.File
}
func main() {
MarkAsScala(reflect.TypeOf(new(ScalaType)))
scala := &ScalaType{
stderr: os.Stderr,
}
cloned := Clone(scala).(*ScalaType)
// cloned is a shadow copy of scala
// so that the pointer value should be the same.
fmt.Println(scala.stderr == cloned.stderr)
}
Output: true
func Slowly ¶
func Slowly(v interface{}) interface{}
Slowly recursively deep clone v to a new value. It marks all cloned values internally, thus it can clone v with cycle pointer.
Slowly works exactly the same as Clone. See Clone doc for more details.
Example ¶
type ListNode struct {
Data int
Next *ListNode
}
node1 := &ListNode{
Data: 1,
}
node2 := &ListNode{
Data: 2,
}
node3 := &ListNode{
Data: 3,
}
node1.Next = node2
node2.Next = node3
node3.Next = node1
// We must use `Slowly` to clone a circular linked list.
node := Slowly(node1).(*ListNode)
for i := 0; i < 10; i++ {
fmt.Println(node.Data)
node = node.Next
}
Output: 1 2 3 1 2 3 1 2 3 1
func Undo ¶
func Undo(v interface{})
Undo discards any change made in wrapped value. If v is not a wrapped value, nothing happens.
func Unwrap ¶
func Unwrap(v interface{}) interface{}
Unwrap returns v's original value if v is a wrapped value. Otherwise, simply returns v itself.
func Wrap ¶
func Wrap(v interface{}) interface{}
Wrap creates a wrapper of v, which must be a pointer. If v is not a pointer, Wrap simply returns v and do nothing.
The wrapper is a deep clone of v's value. It holds a shadow copy to v internally.
t := &T{Foo: 123}
v := Wrap(t).(*T) // v is a clone of t.
reflect.DeepEqual(t, v) == true // v equals t.
v.Foo = 456 // v.Foo is changed, but t.Foo doesn't change.
orig := Unwrap(v) // Use `Unwrap` to discard wrapper and return original value, which is t.
orig.(*T) == t // orig and t is exactly the same.
Undo(v) // Use `Undo` to discard any change on v.
v.Foo == t.Foo // Now, the value of v and t are the same again.
Example ¶
// Suppose we have a type T defined as following.
// type T struct {
// Foo int
// }
v := &T{
Foo: 123,
}
w := Wrap(v).(*T) // Wrap value to protect it.
// Use w freely. The type of w is the same as that of v.
// It's OK to modify w. The change will not affect v.
w.Foo = 456
fmt.Println(w.Foo) // 456
fmt.Println(v.Foo) // 123
// Once we need the original value stored in w, call `Unwrap`.
orig := Unwrap(w).(*T)
fmt.Println(orig == v) // true
fmt.Println(orig.Foo) // 123
// Or, we can simply undo any change made in w.
// Note that `Undo` is significantly slower than `Unwrap`, thus
// the latter is always preferred.
Undo(w)
fmt.Println(w.Foo) // 123
Output: 456 123 true 123 123
Types ¶
This section is empty.