github.com/niubaoshu/goutils@v0.0.0-20180828035119-e8e576f66c2b/deepclone.go (about)

     1  // deepcopy makes deep copies of things. A standard copy will copy the
     2  // pointers: deep copy copies the values pointed to.  Unexported field
     3  // values are not copied.
     4  //
     5  // Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved.
     6  // License: MIT, for more details check the included LICENSE file.
     7  package goutils
     8  
     9  import (
    10  	"reflect"
    11  	"unsafe"
    12  )
    13  
    14  // Copy creates a deep copy of whatever is passed to it and returns the copy
    15  // in an interface{}.  The returned value will need to be asserted to the
    16  // correct type.
    17  func DeepClone(src interface{}) interface{} {
    18  	if src == nil {
    19  		return nil
    20  	}
    21  
    22  	// Make the interface a reflect.Value
    23  	original := reflect.ValueOf(src)
    24  
    25  	// Make a copy of the same type as the original.
    26  	cpy := reflect.New(original.Type()).Elem()
    27  
    28  	// Recursively copy the original.
    29  	copyRecursive(original, cpy)
    30  
    31  	//fmt.Println("original ", original)
    32  	//fmt.Println("copy", cpy)
    33  	// Return the copy as an interface.
    34  	return cpy.Interface()
    35  }
    36  
    37  // copyRecursive does the actual copying of the interface. It currently has
    38  // limited support for what it can handle. Add as needed.
    39  func copyRecursive(original, cpy reflect.Value) {
    40  	// handle according to original's Kind
    41  	switch original.Kind() {
    42  	case reflect.Ptr:
    43  		// Get the actual value being pointed to.
    44  		originalValue := original.Elem()
    45  
    46  		// if  it isn't valid, return.
    47  		if !originalValue.IsValid() {
    48  			return
    49  		}
    50  		cpy.Set(reflect.New(originalValue.Type()))
    51  		copyRecursive(originalValue, cpy.Elem())
    52  
    53  	case reflect.Interface:
    54  		// If this is a nil, don't do anything
    55  		if original.IsNil() {
    56  			return
    57  		}
    58  		// Get the value for the interface, not the pointer.
    59  		originalValue := original.Elem()
    60  
    61  		// Get the value by calling Elem().
    62  		copyValue := reflect.New(originalValue.Type()).Elem()
    63  		copyRecursive(originalValue, copyValue)
    64  		cpy.Set(copyValue)
    65  
    66  	case reflect.Struct:
    67  		for i := 0; i < original.NumField(); i++ {
    68  			field := cpy.Type().Field(i)
    69  			copyRecursive(original.Field(i),
    70  				reflect.NewAt(field.Type, unsafe.Pointer(cpy.Field(i).UnsafeAddr())).Elem())
    71  		}
    72  
    73  	case reflect.Slice:
    74  		if original.IsNil() {
    75  			return
    76  		}
    77  		// Make a new slice and copy each element.
    78  		cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
    79  		for i := 0; i < original.Len(); i++ {
    80  			copyRecursive(original.Index(i), cpy.Index(i))
    81  		}
    82  
    83  	case reflect.Map:
    84  		if original.IsNil() {
    85  			return
    86  		}
    87  		cpy.Set(reflect.MakeMap(original.Type()))
    88  		for _, oKey := range original.MapKeys() {
    89  			cKey := reflect.New(oKey.Type()).Elem()
    90  			oVal := original.MapIndex(oKey)
    91  			cVal := reflect.New(oVal.Type()).Elem()
    92  			copyRecursive(oKey, cKey)
    93  			copyRecursive(oVal, cVal)
    94  			cpy.SetMapIndex(cKey, cVal)
    95  		}
    96  	case reflect.Array:
    97  		for i := 0; i < original.Len(); i++ {
    98  			copyRecursive(original.Index(i), cpy.Index(i))
    99  		}
   100  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   101  		cpy.SetInt(original.Int())
   102  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   103  		cpy.SetUint(original.Uint())
   104  	case reflect.Bool:
   105  		cpy.SetBool(original.Bool())
   106  	case reflect.Float32, reflect.Float64:
   107  		cpy.SetFloat(original.Float())
   108  	case reflect.Complex64, reflect.Complex128:
   109  		cpy.SetComplex(original.Complex())
   110  	case reflect.String:
   111  		cpy.SetString(original.String())
   112  	case reflect.UnsafePointer:
   113  		cpy.SetPointer(unsafe.Pointer(original.Pointer()))
   114  	}
   115  }