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