github.com/wangyougui/gf/v2@v2.6.5/internal/deepcopy/deepcopy.go (about)

     1  // Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/wangyougui/gf.
     6  
     7  // Package deepcopy makes deep copies of things using reflection.
     8  //
     9  // This package is maintained from: https://github.com/mohae/deepcopy
    10  package deepcopy
    11  
    12  import (
    13  	"reflect"
    14  	"time"
    15  )
    16  
    17  // Interface for delegating copy process to type
    18  type Interface interface {
    19  	DeepCopy() interface{}
    20  }
    21  
    22  // Copy creates a deep copy of whatever is passed to it and returns the copy
    23  // in an interface{}.  The returned value will need to be asserted to the
    24  // correct type.
    25  func Copy(src interface{}) interface{} {
    26  	if src == nil {
    27  		return nil
    28  	}
    29  
    30  	// Copy by type assertion.
    31  	switch r := src.(type) {
    32  	case
    33  		int, int8, int16, int32, int64,
    34  		uint, uint8, uint16, uint32, uint64,
    35  		float32, float64,
    36  		complex64, complex128,
    37  		string,
    38  		bool:
    39  		return r
    40  
    41  	default:
    42  		if v, ok := src.(Interface); ok {
    43  			return v.DeepCopy()
    44  		}
    45  		var (
    46  			original = reflect.ValueOf(src)                // Make the interface a reflect.Value
    47  			dst      = reflect.New(original.Type()).Elem() // Make a copy of the same type as the original.
    48  		)
    49  		// Recursively copy the original.
    50  		copyRecursive(original, dst)
    51  		// Return the copy as an interface.
    52  		return dst.Interface()
    53  	}
    54  }
    55  
    56  // copyRecursive does the actual copying of the interface. It currently has
    57  // limited support for what it can handle. Add as needed.
    58  func copyRecursive(original, cpy reflect.Value) {
    59  	// check for implement deepcopy.Interface
    60  	if original.CanInterface() && original.IsValid() && !original.IsZero() {
    61  		if copier, ok := original.Interface().(Interface); ok {
    62  			cpy.Set(reflect.ValueOf(copier.DeepCopy()))
    63  			return
    64  		}
    65  	}
    66  
    67  	// handle according to original's Kind
    68  	switch original.Kind() {
    69  	case reflect.Ptr:
    70  		// Get the actual value being pointed to.
    71  		originalValue := original.Elem()
    72  
    73  		// if  it isn't valid, return.
    74  		if !originalValue.IsValid() {
    75  			return
    76  		}
    77  		cpy.Set(reflect.New(originalValue.Type()))
    78  		copyRecursive(originalValue, cpy.Elem())
    79  
    80  	case reflect.Interface:
    81  		// If this is a nil, don't do anything
    82  		if original.IsNil() {
    83  			return
    84  		}
    85  		// Get the value for the interface, not the pointer.
    86  		originalValue := original.Elem()
    87  
    88  		// Get the value by calling Elem().
    89  		copyValue := reflect.New(originalValue.Type()).Elem()
    90  		copyRecursive(originalValue, copyValue)
    91  		cpy.Set(copyValue)
    92  
    93  	case reflect.Struct:
    94  		t, ok := original.Interface().(time.Time)
    95  		if ok {
    96  			cpy.Set(reflect.ValueOf(t))
    97  			return
    98  		}
    99  		// Go through each field of the struct and copy it.
   100  		for i := 0; i < original.NumField(); i++ {
   101  			// The Type's StructField for a given field is checked to see if StructField.PkgPath
   102  			// is set to determine if the field is exported or not because CanSet() returns false
   103  			// for settable fields.  I'm not sure why.  -mohae
   104  			if original.Type().Field(i).PkgPath != "" {
   105  				continue
   106  			}
   107  			copyRecursive(original.Field(i), cpy.Field(i))
   108  		}
   109  
   110  	case reflect.Slice:
   111  		if original.IsNil() {
   112  			return
   113  		}
   114  		// Make a new slice and copy each element.
   115  		cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
   116  		for i := 0; i < original.Len(); i++ {
   117  			copyRecursive(original.Index(i), cpy.Index(i))
   118  		}
   119  
   120  	case reflect.Map:
   121  		if original.IsNil() {
   122  			return
   123  		}
   124  		cpy.Set(reflect.MakeMap(original.Type()))
   125  		for _, key := range original.MapKeys() {
   126  			originalValue := original.MapIndex(key)
   127  			copyValue := reflect.New(originalValue.Type()).Elem()
   128  			copyRecursive(originalValue, copyValue)
   129  			copyKey := Copy(key.Interface())
   130  			cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
   131  		}
   132  
   133  	default:
   134  		cpy.Set(original)
   135  	}
   136  }