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