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
		
	
| 
											2 years ago
										 | package tools | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"fmt" | ||
|  | 	"reflect" | ||
|  | 	"time" | ||
|  | ) | ||
|  | 
 | ||
| 
											2 years ago
										 | // both function should call with input type of struct or pointer of struct
 | ||
| 
											2 years ago
										 | 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: | ||
| 
											2 years ago
										 | 		// get the value for the in_obj, not the pointer.
 | ||
| 
											2 years ago
										 | 		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 + " }" | ||
|  | } |