You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.5 KiB
Go
144 lines
3.5 KiB
Go
package tools
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"time"
|
|
)
|
|
|
|
// both function should call with input type of struct or pointer of struct
|
|
func DeepCopy(origin interface{}) interface{} {
|
|
if origin == nil {
|
|
return nil
|
|
}
|
|
original := reflect.ValueOf(origin)
|
|
cpy := reflect.New(original.Type()).Elem()
|
|
copyRecursive(original, cpy)
|
|
return cpy.Interface()
|
|
}
|
|
|
|
var _timeType = reflect.TypeOf(time.Time{})
|
|
|
|
func copyRecursive(original, cpy reflect.Value) {
|
|
// handle according to original's Kind
|
|
if !cpy.CanSet() {
|
|
return
|
|
}
|
|
|
|
switch original.Kind() {
|
|
case reflect.Ptr:
|
|
// get the actual value being pointed to.
|
|
originalValue := original.Elem()
|
|
// if it isn't valid, return.
|
|
if !originalValue.IsValid() {
|
|
return
|
|
}
|
|
cpy.Set(reflect.New(originalValue.Type()))
|
|
copyRecursive(originalValue, cpy.Elem())
|
|
case reflect.Interface:
|
|
// get the value for the in_obj, not the pointer.
|
|
originalValue := original.Elem()
|
|
if !originalValue.IsValid() {
|
|
return
|
|
}
|
|
// get the value by calling Elem().
|
|
copyValue := reflect.New(originalValue.Type()).Elem()
|
|
copyRecursive(originalValue, copyValue)
|
|
cpy.Set(copyValue)
|
|
case reflect.Struct:
|
|
oriType := original.Type()
|
|
|
|
// Go through each field of the struct and copy it.
|
|
if oriType.ConvertibleTo(_timeType) {
|
|
t := original.Convert(_timeType)
|
|
cpy.Set(t)
|
|
return
|
|
}
|
|
for i := 0; i < original.NumField(); i++ {
|
|
if cpy.Field(i).CanSet() &&
|
|
(oriType.Field(i).Tag.Get("json") != "-" || oriType.Field(i).Tag.Get("cpy") != "") {
|
|
copyRecursive(original.Field(i), cpy.Field(i))
|
|
}
|
|
}
|
|
case reflect.Slice:
|
|
// Make a new slice and copy each element.
|
|
cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
|
|
for i := 0; i < original.Len(); i++ {
|
|
copyRecursive(original.Index(i), cpy.Index(i))
|
|
}
|
|
case reflect.Map:
|
|
if original.IsNil() {
|
|
return
|
|
}
|
|
cpy.Set(reflect.MakeMap(original.Type()))
|
|
for _, key := range original.MapKeys() {
|
|
originalValue := original.MapIndex(key)
|
|
copyValue := reflect.New(originalValue.Type()).Elem()
|
|
copyRecursive(originalValue, copyValue)
|
|
cpy.SetMapIndex(key, copyValue)
|
|
}
|
|
// Sets the actual values from here on.
|
|
default:
|
|
cpy.Set(original)
|
|
}
|
|
}
|
|
|
|
func InterfacePresentation(record interface{}) string {
|
|
if reflect.TypeOf(record).Kind() != reflect.Ptr {
|
|
return fmt.Sprint(record)
|
|
}
|
|
|
|
s := "{ "
|
|
structType := reflect.TypeOf(record).Elem()
|
|
structValue := reflect.ValueOf(record).Elem()
|
|
if !structValue.IsValid() {
|
|
return "(nil/zero)"
|
|
}
|
|
fieldNum := structValue.NumField()
|
|
for i := 0; i < fieldNum; i++ {
|
|
fieldType := structType.Field(i)
|
|
fieldValue := structValue.Field(i)
|
|
s += fieldType.Name + ": "
|
|
if !fieldValue.CanInterface() {
|
|
s += "(can not read)"
|
|
continue
|
|
}
|
|
switch fieldType.Type.Kind() {
|
|
case reflect.Struct:
|
|
s += InterfacePresentation(fieldValue.Addr().Interface())
|
|
case reflect.Array, reflect.Slice:
|
|
s += "< "
|
|
la := fieldValue.Len()
|
|
for j := 0; j < la; j++ {
|
|
elemValue := fieldValue.Index(j)
|
|
s += InterfacePresentation(elemValue.Interface())
|
|
if la != j+1 {
|
|
s += ", "
|
|
}
|
|
}
|
|
s += " >"
|
|
case reflect.Map:
|
|
s += "map[ "
|
|
lm := len(fieldValue.MapKeys())
|
|
j := 0
|
|
for _, key := range fieldValue.MapKeys() {
|
|
elemValue := fieldValue.MapIndex(key)
|
|
s += key.String() + ": " + InterfacePresentation(elemValue.Interface())
|
|
if lm != j+1 {
|
|
s += ", "
|
|
}
|
|
j += 1
|
|
}
|
|
s += " ]"
|
|
case reflect.Ptr:
|
|
s += InterfacePresentation(fieldValue.Interface())
|
|
default:
|
|
s += fmt.Sprint(fieldValue)
|
|
}
|
|
if i != fieldNum-1 {
|
|
s += ", "
|
|
}
|
|
}
|
|
return s + " }"
|
|
}
|