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

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 + " }"
}