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 }