copystructure

repository·master·Indexed 18 days ago

https://github.com/mitchellh/copystructure

A Go library for performing deep copies of values, ensuring that reference types like maps, slices, and pointers are copied by value. It supports custom copy behavior via the `copy` struct tag, a `Config` struct for locking and custom copiers, and global registration maps for specific type handling.

Tokens
1.4K
Snippets
7
Records
8
Agent score
13%

What's inside copystructure

  1. Deep copy Go values with copystructure

    master
    The copystructure library provides a way to perform deep copies of Go values. Unlike a shallow copy which only copies references, copystructure copies the underlying data for reference types such as maps, slices, or pointers. This ensures that the new value is entirely independent of the original.
  2. Register types for shallow copying

    master

    To ensure certain types are always shallow copied (the pointer/reference is copied, but the underlying data is not), add their reflect.Type to the ShallowCopiers map.

    Global Registration: Use copystructure.ShallowCopiers.

    Local Registration: Use the ShallowCopiers field in a copystructure.Config instance.

    Warning: Like Copiers, it is unsafe to write to this map while a copy operation is in progress. Use a mutex for concurrent access.

    // Always shallow copy *bytes.Buffer
    copystructure.ShallowCopiers[reflect.TypeOf(&bytes.Buffer{})] = struct{}{}
  3. Register custom type copiers

    master

    You can define how specific types are copied by providing a CopierFunc. This is useful for types that require special handling (e.g., types with internal state that shouldn't be reflected).

    Global Registration: Register functions in the copystructure.Copiers map. The key must be the reflect.Type of the value.

    Local Registration: Pass a custom map to the Copiers field of a copystructure.Config instance to avoid affecting global state.

    Warning: It is unsafe to write to the Copiers map while a copy operation is in progress. If you must modify the map concurrently, wrap both the modifications and the Copy calls in a mutex.

    CopierFunc Signature: type CopierFunc func(interface{}) (interface{}, error)

    type MySpecialType struct {
    	Value int
    }
    
    copier := func(v interface{}) (interface{}, error) {
    	t := v.(MySpecialType)
    	return MySpecialType{Value: t.Value}, nil
    }
    
    // Register globally
    copystructure.Copiers[reflect.TypeOf(MySpecialType{})] = copier
  4. Use Must() for panic-on-error copying

    master

    The copystructure.Must helper is a convenience function for variable initializations where a copy error should be treated as a fatal error (causing a panic).

    Signature: func Must(v interface{}, err error) interface{}

    // Use in global or package-level variable initialization
    var clonedData = copystructure.Must(copystructure.Copy(originalData))
  5. Configure deep copy behavior with Config

    master

    For more control over the copying process, use the Config struct with the Copy method instead of the package-level Copy function.

    Config Fields:

    • Lock (bool): If true, the copier will attempt to lock any types that implement sync.Locker (excluding sync.Mutex and sync.RWMutex directly) while walking the structure. Note: When Lock is true, the argument passed to Copy must be a pointer.
    • Copiers (map[reflect.Type]CopierFunc): A map of custom functions used to deep copy specific types. If nil, the global copystructure.Copiers map is used.
    • ShallowCopiers (map[reflect.Type]struct{}): A map of types that will always be shallow copied. If nil, the global copystructure.ShallowCopiers map is used.
    cfg := copystructure.Config{
    	Lock: true,
    }
    // Note: v must be a pointer if Lock is true
    newVal, err := cfg.Copy(&originalVal)
  6. Deep copy a Go value with Copy()

    master

    Use copystructure.Copy(v) to create a deep copy of a value v.

    Limitations:

    • It cannot copy unexported fields (lowercase field names) because they cannot be accessed via reflection.
    • For structs, you can control copy behavior using the copy struct tag.

    Available Struct Tags:

    • copy:"ignore": The field is ignored and assigned its zero value in the copy.
    • copy:"shallow": The field is shallow copied (pointers, maps, and slices are directly assigned rather than deep copied).

    Example:

    type MyStruct struct {
    	Name string
    	Data *bytes.Buffer `copy:"shallow"` // This pointer will be copied directly
    	Secret string `copy:"ignore"`        // This field will be zeroed
    }
    
    // Usage
    newVal, err := copystructure.Copy(originalVal)
    newVal, err := copystructure.Copy(originalVal)
  7. Reference: Copystructure Configuration Options

    master

    The following maps allow for customizing the deep copy behavior for specific types.

    // Copiers: map[reflect.Type]CopierFunc
    // Key: reflect.TypeOf(value)
    // Value: Function that performs the copy
    var Copiers map[reflect.Type]CopierFunc
    
    // ShallowCopiers: map[reflect.Type]struct{}
    // Key: reflect.TypeOf(pointer_to_value)
    // Value: Empty struct
    var ShallowCopiers map[reflect.Type]struct{}