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 }