github.com/wangyougui/gf/v2@v2.6.5/util/gconv/gconv_convert.go (about)

     1  // Copyright GoFrame 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 gconv
     8  
     9  import (
    10  	"reflect"
    11  	"time"
    12  
    13  	"github.com/wangyougui/gf/v2/os/gtime"
    14  )
    15  
    16  // Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.
    17  //
    18  // The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
    19  // It supports common basic types conversion as its conversion based on type name string.
    20  func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} {
    21  	return doConvert(doConvertInput{
    22  		FromValue:  fromValue,
    23  		ToTypeName: toTypeName,
    24  		ReferValue: nil,
    25  		Extra:      extraParams,
    26  	})
    27  }
    28  
    29  // ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`.
    30  //
    31  // The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
    32  // It supports common basic types conversion as its conversion based on type name string.
    33  func ConvertWithRefer(fromValue interface{}, referValue interface{}, extraParams ...interface{}) interface{} {
    34  	var referValueRf reflect.Value
    35  	if v, ok := referValue.(reflect.Value); ok {
    36  		referValueRf = v
    37  	} else {
    38  		referValueRf = reflect.ValueOf(referValue)
    39  	}
    40  	return doConvert(doConvertInput{
    41  		FromValue:  fromValue,
    42  		ToTypeName: referValueRf.Type().String(),
    43  		ReferValue: referValue,
    44  		Extra:      extraParams,
    45  	})
    46  }
    47  
    48  type doConvertInput struct {
    49  	FromValue  interface{}   // Value that is converted from.
    50  	ToTypeName string        // Target value type name in string.
    51  	ReferValue interface{}   // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value.
    52  	Extra      []interface{} // Extra values for implementing the converting.
    53  	// Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result.
    54  	// It is an attribute for internal usage purpose.
    55  	alreadySetToReferValue bool
    56  }
    57  
    58  // doConvert does commonly use types converting.
    59  func doConvert(in doConvertInput) (convertedValue interface{}) {
    60  	switch in.ToTypeName {
    61  	case "int":
    62  		return Int(in.FromValue)
    63  	case "*int":
    64  		if _, ok := in.FromValue.(*int); ok {
    65  			return in.FromValue
    66  		}
    67  		v := Int(in.FromValue)
    68  		return &v
    69  
    70  	case "int8":
    71  		return Int8(in.FromValue)
    72  	case "*int8":
    73  		if _, ok := in.FromValue.(*int8); ok {
    74  			return in.FromValue
    75  		}
    76  		v := Int8(in.FromValue)
    77  		return &v
    78  
    79  	case "int16":
    80  		return Int16(in.FromValue)
    81  	case "*int16":
    82  		if _, ok := in.FromValue.(*int16); ok {
    83  			return in.FromValue
    84  		}
    85  		v := Int16(in.FromValue)
    86  		return &v
    87  
    88  	case "int32":
    89  		return Int32(in.FromValue)
    90  	case "*int32":
    91  		if _, ok := in.FromValue.(*int32); ok {
    92  			return in.FromValue
    93  		}
    94  		v := Int32(in.FromValue)
    95  		return &v
    96  
    97  	case "int64":
    98  		return Int64(in.FromValue)
    99  	case "*int64":
   100  		if _, ok := in.FromValue.(*int64); ok {
   101  			return in.FromValue
   102  		}
   103  		v := Int64(in.FromValue)
   104  		return &v
   105  
   106  	case "uint":
   107  		return Uint(in.FromValue)
   108  	case "*uint":
   109  		if _, ok := in.FromValue.(*uint); ok {
   110  			return in.FromValue
   111  		}
   112  		v := Uint(in.FromValue)
   113  		return &v
   114  
   115  	case "uint8":
   116  		return Uint8(in.FromValue)
   117  	case "*uint8":
   118  		if _, ok := in.FromValue.(*uint8); ok {
   119  			return in.FromValue
   120  		}
   121  		v := Uint8(in.FromValue)
   122  		return &v
   123  
   124  	case "uint16":
   125  		return Uint16(in.FromValue)
   126  	case "*uint16":
   127  		if _, ok := in.FromValue.(*uint16); ok {
   128  			return in.FromValue
   129  		}
   130  		v := Uint16(in.FromValue)
   131  		return &v
   132  
   133  	case "uint32":
   134  		return Uint32(in.FromValue)
   135  	case "*uint32":
   136  		if _, ok := in.FromValue.(*uint32); ok {
   137  			return in.FromValue
   138  		}
   139  		v := Uint32(in.FromValue)
   140  		return &v
   141  
   142  	case "uint64":
   143  		return Uint64(in.FromValue)
   144  	case "*uint64":
   145  		if _, ok := in.FromValue.(*uint64); ok {
   146  			return in.FromValue
   147  		}
   148  		v := Uint64(in.FromValue)
   149  		return &v
   150  
   151  	case "float32":
   152  		return Float32(in.FromValue)
   153  	case "*float32":
   154  		if _, ok := in.FromValue.(*float32); ok {
   155  			return in.FromValue
   156  		}
   157  		v := Float32(in.FromValue)
   158  		return &v
   159  
   160  	case "float64":
   161  		return Float64(in.FromValue)
   162  	case "*float64":
   163  		if _, ok := in.FromValue.(*float64); ok {
   164  			return in.FromValue
   165  		}
   166  		v := Float64(in.FromValue)
   167  		return &v
   168  
   169  	case "bool":
   170  		return Bool(in.FromValue)
   171  	case "*bool":
   172  		if _, ok := in.FromValue.(*bool); ok {
   173  			return in.FromValue
   174  		}
   175  		v := Bool(in.FromValue)
   176  		return &v
   177  
   178  	case "string":
   179  		return String(in.FromValue)
   180  	case "*string":
   181  		if _, ok := in.FromValue.(*string); ok {
   182  			return in.FromValue
   183  		}
   184  		v := String(in.FromValue)
   185  		return &v
   186  
   187  	case "[]byte":
   188  		return Bytes(in.FromValue)
   189  	case "[]int":
   190  		return Ints(in.FromValue)
   191  	case "[]int32":
   192  		return Int32s(in.FromValue)
   193  	case "[]int64":
   194  		return Int64s(in.FromValue)
   195  	case "[]uint":
   196  		return Uints(in.FromValue)
   197  	case "[]uint8":
   198  		return Bytes(in.FromValue)
   199  	case "[]uint32":
   200  		return Uint32s(in.FromValue)
   201  	case "[]uint64":
   202  		return Uint64s(in.FromValue)
   203  	case "[]float32":
   204  		return Float32s(in.FromValue)
   205  	case "[]float64":
   206  		return Float64s(in.FromValue)
   207  	case "[]string":
   208  		return Strings(in.FromValue)
   209  
   210  	case "Time", "time.Time":
   211  		if len(in.Extra) > 0 {
   212  			return Time(in.FromValue, String(in.Extra[0]))
   213  		}
   214  		return Time(in.FromValue)
   215  	case "*time.Time":
   216  		var v time.Time
   217  		if len(in.Extra) > 0 {
   218  			v = Time(in.FromValue, String(in.Extra[0]))
   219  		} else {
   220  			if _, ok := in.FromValue.(*time.Time); ok {
   221  				return in.FromValue
   222  			}
   223  			v = Time(in.FromValue)
   224  		}
   225  		return &v
   226  
   227  	case "GTime", "gtime.Time":
   228  		if len(in.Extra) > 0 {
   229  			if v := GTime(in.FromValue, String(in.Extra[0])); v != nil {
   230  				return *v
   231  			} else {
   232  				return *gtime.New()
   233  			}
   234  		}
   235  		if v := GTime(in.FromValue); v != nil {
   236  			return *v
   237  		} else {
   238  			return *gtime.New()
   239  		}
   240  	case "*gtime.Time":
   241  		if len(in.Extra) > 0 {
   242  			if v := GTime(in.FromValue, String(in.Extra[0])); v != nil {
   243  				return v
   244  			} else {
   245  				return gtime.New()
   246  			}
   247  		}
   248  		if v := GTime(in.FromValue); v != nil {
   249  			return v
   250  		} else {
   251  			return gtime.New()
   252  		}
   253  
   254  	case "Duration", "time.Duration":
   255  		return Duration(in.FromValue)
   256  	case "*time.Duration":
   257  		if _, ok := in.FromValue.(*time.Duration); ok {
   258  			return in.FromValue
   259  		}
   260  		v := Duration(in.FromValue)
   261  		return &v
   262  
   263  	case "map[string]string":
   264  		return MapStrStr(in.FromValue)
   265  
   266  	case "map[string]interface{}":
   267  		return Map(in.FromValue)
   268  
   269  	case "[]map[string]interface{}":
   270  		return Maps(in.FromValue)
   271  
   272  	case "RawMessage", "json.RawMessage":
   273  		return Bytes(in.FromValue)
   274  
   275  	default:
   276  		if in.ReferValue != nil {
   277  			var referReflectValue reflect.Value
   278  			if v, ok := in.ReferValue.(reflect.Value); ok {
   279  				referReflectValue = v
   280  			} else {
   281  				referReflectValue = reflect.ValueOf(in.ReferValue)
   282  			}
   283  			var fromReflectValue reflect.Value
   284  			if v, ok := in.FromValue.(reflect.Value); ok {
   285  				fromReflectValue = v
   286  			} else {
   287  				fromReflectValue = reflect.ValueOf(in.FromValue)
   288  			}
   289  
   290  			// custom converter.
   291  			if dstReflectValue, ok, _ := callCustomConverterWithRefer(fromReflectValue, referReflectValue); ok {
   292  				return dstReflectValue.Interface()
   293  			}
   294  
   295  			defer func() {
   296  				if recover() != nil {
   297  					in.alreadySetToReferValue = false
   298  					if err := bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil {
   299  						in.alreadySetToReferValue = true
   300  						convertedValue = referReflectValue.Interface()
   301  					}
   302  				}
   303  			}()
   304  			switch referReflectValue.Kind() {
   305  			case reflect.Ptr:
   306  				// Type converting for custom type pointers.
   307  				// Eg:
   308  				// type PayMode int
   309  				// type Req struct{
   310  				//     Mode *PayMode
   311  				// }
   312  				//
   313  				// Struct(`{"Mode": 1000}`, &req)
   314  				originType := referReflectValue.Type().Elem()
   315  				switch originType.Kind() {
   316  				case reflect.Struct:
   317  					// Not support some kinds.
   318  				default:
   319  					in.ToTypeName = originType.Kind().String()
   320  					in.ReferValue = nil
   321  					refElementValue := reflect.ValueOf(doConvert(in))
   322  					originTypeValue := reflect.New(refElementValue.Type()).Elem()
   323  					originTypeValue.Set(refElementValue)
   324  					in.alreadySetToReferValue = true
   325  					return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface()
   326  				}
   327  
   328  			case reflect.Map:
   329  				var targetValue = reflect.New(referReflectValue.Type()).Elem()
   330  				if err := doMapToMap(in.FromValue, targetValue); err == nil {
   331  					in.alreadySetToReferValue = true
   332  				}
   333  				return targetValue.Interface()
   334  			}
   335  			in.ToTypeName = referReflectValue.Kind().String()
   336  			in.ReferValue = nil
   337  			in.alreadySetToReferValue = true
   338  			convertedValue = reflect.ValueOf(doConvert(in)).Convert(referReflectValue.Type()).Interface()
   339  			return convertedValue
   340  		}
   341  		return in.FromValue
   342  	}
   343  }
   344  
   345  func doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) {
   346  	convertedValue := doConvert(in)
   347  	if !in.alreadySetToReferValue {
   348  		reflectValue.Set(reflect.ValueOf(convertedValue))
   349  	}
   350  }