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 }