github.com/sandwich-go/boost@v1.3.29/xcopy/deep.go (about)

     1  package xcopy
     2  
     3  import (
     4  	"reflect"
     5  	"time"
     6  
     7  	proto1 "github.com/golang/protobuf/proto"
     8  	proto2 "google.golang.org/protobuf/proto"
     9  )
    10  
    11  // DeepCopyInterface for delegating copy process to type
    12  type DeepCopyInterface interface {
    13  	DeepCopy() interface{}
    14  }
    15  
    16  func fastDeepCopy(src interface{}) (interface{}, bool) {
    17  	switch v := src.(type) {
    18  	case interface{ Clone() proto1.Message }:
    19  		// protokitgo 激活 golang.proto_enable_clone 属性加速拷贝
    20  		return v.Clone(), true
    21  	case interface{ Clone() proto2.Message }:
    22  		// protokitgo 激活 golang.proto_enable_clone 属性加速拷贝
    23  		return v.Clone(), true
    24  	case DeepCopyInterface:
    25  		return v.DeepCopy(), true
    26  	}
    27  	return nil, false
    28  }
    29  
    30  // DeepCopy creates a deep copy of whatever is passed to it and returns the copy
    31  // in an interface{}.  The returned value will need to be asserted to the
    32  // correct type.
    33  // 1. if src has 'Clone() proto1.Message' function, use src.Clone()
    34  // 2. if src has 'Clone() proto2.Message' function, use src.Clone()
    35  // 3. if src has 'DeepCopy() interface{}' function, use src.DeepCopy()
    36  func DeepCopy(src interface{}) interface{} {
    37  	if src == nil {
    38  		return nil
    39  	}
    40  
    41  	if dest, ok := fastDeepCopy(src); ok {
    42  		return dest
    43  	}
    44  
    45  	// Make the interface a reflect.Value
    46  	original := reflect.ValueOf(src)
    47  
    48  	// Make a copy of the same type as the original.
    49  	cpy := reflect.New(original.Type()).Elem()
    50  
    51  	// Recursively copy the original.
    52  	copyRecursive(original, cpy)
    53  
    54  	// Return the copy as an interface.
    55  	return cpy.Interface()
    56  }
    57  
    58  // copyRecursive does the actual copying of the interface. It currently has
    59  // limited support for what it can handle. Add as needed.
    60  func copyRecursive(original, cpy reflect.Value) {
    61  	// check for implement deepcopy.Interface
    62  	if original.CanInterface() {
    63  		if dest, ok := fastDeepCopy(original.Interface()); ok {
    64  			cpy.Set(reflect.ValueOf(dest))
    65  			return
    66  		}
    67  	}
    68  
    69  	// handle according to original's Kind
    70  	switch original.Kind() {
    71  	case reflect.Ptr:
    72  		// Get the actual value being pointed to.
    73  		originalValue := original.Elem()
    74  
    75  		// if  it isn't valid, return.
    76  		if !originalValue.IsValid() {
    77  			return
    78  		}
    79  		cpy.Set(reflect.New(originalValue.Type()))
    80  		copyRecursive(originalValue, cpy.Elem())
    81  
    82  	case reflect.Interface:
    83  		// If this is a nil, don't do anything
    84  		if original.IsNil() {
    85  			return
    86  		}
    87  		// Get the value for the interface, not the pointer.
    88  		originalValue := original.Elem()
    89  
    90  		// Get the value by calling Elem().
    91  		copyValue := reflect.New(originalValue.Type()).Elem()
    92  		copyRecursive(originalValue, copyValue)
    93  		cpy.Set(copyValue)
    94  
    95  	case reflect.Struct:
    96  		t, ok := original.Interface().(time.Time)
    97  		if ok {
    98  			cpy.Set(reflect.ValueOf(t))
    99  			return
   100  		}
   101  		// Go through each field of the struct and copy it.
   102  		for i := 0; i < original.NumField(); i++ {
   103  			// The Type's StructField for a given field is checked to see if StructField.PkgPath
   104  			// is set to determine if the field is exported or not because CanSet() returns false
   105  			// for settable fields.  I'm not sure why.  -mohae
   106  			if original.Type().Field(i).PkgPath != "" {
   107  				continue
   108  			}
   109  			copyRecursive(original.Field(i), cpy.Field(i))
   110  		}
   111  
   112  	case reflect.Slice:
   113  		if original.IsNil() {
   114  			return
   115  		}
   116  		// Make a new slice and copy each element.
   117  		cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
   118  		for i := 0; i < original.Len(); i++ {
   119  			copyRecursive(original.Index(i), cpy.Index(i))
   120  		}
   121  
   122  	case reflect.Map:
   123  		if original.IsNil() {
   124  			return
   125  		}
   126  		cpy.Set(reflect.MakeMap(original.Type()))
   127  		for _, key := range original.MapKeys() {
   128  			originalValue := original.MapIndex(key)
   129  			copyValue := reflect.New(originalValue.Type()).Elem()
   130  			copyRecursive(originalValue, copyValue)
   131  			copyKey := DeepCopy(key.Interface())
   132  			cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
   133  		}
   134  
   135  	default:
   136  		cpy.Set(original)
   137  	}
   138  }