123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
- //
- // This Source Code Form is subject to the terms of the MIT License.
- // If a copy of the MIT was not distributed with this file,
- // You can obtain one at https://github.com/gogf/gf.
- package gconv
- import (
- "reflect"
- "time"
- "github.com/gogf/gf/v2/os/gtime"
- )
- // Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.
- //
- // The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
- // It supports common basic types conversion as its conversion based on type name string.
- func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} {
- return doConvert(doConvertInput{
- FromValue: fromValue,
- ToTypeName: toTypeName,
- ReferValue: nil,
- Extra: extraParams,
- })
- }
- // ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`.
- //
- // The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
- // It supports common basic types conversion as its conversion based on type name string.
- func ConvertWithRefer(fromValue interface{}, referValue interface{}, extraParams ...interface{}) interface{} {
- var referValueRf reflect.Value
- if v, ok := referValue.(reflect.Value); ok {
- referValueRf = v
- } else {
- referValueRf = reflect.ValueOf(referValue)
- }
- return doConvert(doConvertInput{
- FromValue: fromValue,
- ToTypeName: referValueRf.Type().String(),
- ReferValue: referValue,
- Extra: extraParams,
- })
- }
- type doConvertInput struct {
- FromValue interface{} // Value that is converted from.
- ToTypeName string // Target value type name in string.
- ReferValue interface{} // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value.
- Extra []interface{} // Extra values for implementing the converting.
- // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result.
- // It is an attribute for internal usage purpose.
- alreadySetToReferValue bool
- }
- // doConvert does commonly use types converting.
- func doConvert(in doConvertInput) (convertedValue interface{}) {
- switch in.ToTypeName {
- case "int":
- return Int(in.FromValue)
- case "*int":
- if _, ok := in.FromValue.(*int); ok {
- return in.FromValue
- }
- v := Int(in.FromValue)
- return &v
- case "int8":
- return Int8(in.FromValue)
- case "*int8":
- if _, ok := in.FromValue.(*int8); ok {
- return in.FromValue
- }
- v := Int8(in.FromValue)
- return &v
- case "int16":
- return Int16(in.FromValue)
- case "*int16":
- if _, ok := in.FromValue.(*int16); ok {
- return in.FromValue
- }
- v := Int16(in.FromValue)
- return &v
- case "int32":
- return Int32(in.FromValue)
- case "*int32":
- if _, ok := in.FromValue.(*int32); ok {
- return in.FromValue
- }
- v := Int32(in.FromValue)
- return &v
- case "int64":
- return Int64(in.FromValue)
- case "*int64":
- if _, ok := in.FromValue.(*int64); ok {
- return in.FromValue
- }
- v := Int64(in.FromValue)
- return &v
- case "uint":
- return Uint(in.FromValue)
- case "*uint":
- if _, ok := in.FromValue.(*uint); ok {
- return in.FromValue
- }
- v := Uint(in.FromValue)
- return &v
- case "uint8":
- return Uint8(in.FromValue)
- case "*uint8":
- if _, ok := in.FromValue.(*uint8); ok {
- return in.FromValue
- }
- v := Uint8(in.FromValue)
- return &v
- case "uint16":
- return Uint16(in.FromValue)
- case "*uint16":
- if _, ok := in.FromValue.(*uint16); ok {
- return in.FromValue
- }
- v := Uint16(in.FromValue)
- return &v
- case "uint32":
- return Uint32(in.FromValue)
- case "*uint32":
- if _, ok := in.FromValue.(*uint32); ok {
- return in.FromValue
- }
- v := Uint32(in.FromValue)
- return &v
- case "uint64":
- return Uint64(in.FromValue)
- case "*uint64":
- if _, ok := in.FromValue.(*uint64); ok {
- return in.FromValue
- }
- v := Uint64(in.FromValue)
- return &v
- case "float32":
- return Float32(in.FromValue)
- case "*float32":
- if _, ok := in.FromValue.(*float32); ok {
- return in.FromValue
- }
- v := Float32(in.FromValue)
- return &v
- case "float64":
- return Float64(in.FromValue)
- case "*float64":
- if _, ok := in.FromValue.(*float64); ok {
- return in.FromValue
- }
- v := Float64(in.FromValue)
- return &v
- case "bool":
- return Bool(in.FromValue)
- case "*bool":
- if _, ok := in.FromValue.(*bool); ok {
- return in.FromValue
- }
- v := Bool(in.FromValue)
- return &v
- case "string":
- return String(in.FromValue)
- case "*string":
- if _, ok := in.FromValue.(*string); ok {
- return in.FromValue
- }
- v := String(in.FromValue)
- return &v
- case "[]byte":
- return Bytes(in.FromValue)
- case "[]int":
- return Ints(in.FromValue)
- case "[]int32":
- return Int32s(in.FromValue)
- case "[]int64":
- return Int64s(in.FromValue)
- case "[]uint":
- return Uints(in.FromValue)
- case "[]uint8":
- return Bytes(in.FromValue)
- case "[]uint32":
- return Uint32s(in.FromValue)
- case "[]uint64":
- return Uint64s(in.FromValue)
- case "[]float32":
- return Float32s(in.FromValue)
- case "[]float64":
- return Float64s(in.FromValue)
- case "[]string":
- return Strings(in.FromValue)
- case "Time", "time.Time":
- if len(in.Extra) > 0 {
- return Time(in.FromValue, String(in.Extra[0]))
- }
- return Time(in.FromValue)
- case "*time.Time":
- var v time.Time
- if len(in.Extra) > 0 {
- v = Time(in.FromValue, String(in.Extra[0]))
- } else {
- if _, ok := in.FromValue.(*time.Time); ok {
- return in.FromValue
- }
- v = Time(in.FromValue)
- }
- return &v
- case "GTime", "gtime.Time":
- if len(in.Extra) > 0 {
- if v := GTime(in.FromValue, String(in.Extra[0])); v != nil {
- return *v
- } else {
- return *gtime.New()
- }
- }
- if v := GTime(in.FromValue); v != nil {
- return *v
- } else {
- return *gtime.New()
- }
- case "*gtime.Time":
- if len(in.Extra) > 0 {
- if v := GTime(in.FromValue, String(in.Extra[0])); v != nil {
- return v
- } else {
- return gtime.New()
- }
- }
- if v := GTime(in.FromValue); v != nil {
- return v
- } else {
- return gtime.New()
- }
- case "Duration", "time.Duration":
- return Duration(in.FromValue)
- case "*time.Duration":
- if _, ok := in.FromValue.(*time.Duration); ok {
- return in.FromValue
- }
- v := Duration(in.FromValue)
- return &v
- case "map[string]string":
- return MapStrStr(in.FromValue)
- case "map[string]interface{}":
- return Map(in.FromValue)
- case "[]map[string]interface{}":
- return Maps(in.FromValue)
- case "RawMessage", "json.RawMessage":
- return Bytes(in.FromValue)
- default:
- if in.ReferValue != nil {
- var referReflectValue reflect.Value
- if v, ok := in.ReferValue.(reflect.Value); ok {
- referReflectValue = v
- } else {
- referReflectValue = reflect.ValueOf(in.ReferValue)
- }
- defer func() {
- if recover() != nil {
- in.alreadySetToReferValue = false
- if err := bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil {
- in.alreadySetToReferValue = true
- convertedValue = referReflectValue.Interface()
- }
- }
- }()
- switch referReflectValue.Kind() {
- case reflect.Ptr:
- // Type converting for custom type pointers.
- // Eg:
- // type PayMode int
- // type Req struct{
- // Mode *PayMode
- // }
- //
- // Struct(`{"Mode": 1000}`, &req)
- originType := referReflectValue.Type().Elem()
- switch originType.Kind() {
- case reflect.Struct:
- // Not support some kinds.
- default:
- in.ToTypeName = originType.Kind().String()
- in.ReferValue = nil
- refElementValue := reflect.ValueOf(doConvert(in))
- originTypeValue := reflect.New(refElementValue.Type()).Elem()
- originTypeValue.Set(refElementValue)
- in.alreadySetToReferValue = true
- return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface()
- }
- case reflect.Map:
- var targetValue = reflect.New(referReflectValue.Type()).Elem()
- if err := doMapToMap(in.FromValue, targetValue); err == nil {
- in.alreadySetToReferValue = true
- }
- return targetValue.Interface()
- }
- in.ToTypeName = referReflectValue.Kind().String()
- in.ReferValue = nil
- in.alreadySetToReferValue = true
- convertedValue = reflect.ValueOf(doConvert(in)).Convert(referReflectValue.Type()).Interface()
- return convertedValue
- }
- return in.FromValue
- }
- }
- func doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) {
- convertedValue := doConvert(in)
- if !in.alreadySetToReferValue {
- reflectValue.Set(reflect.ValueOf(convertedValue))
- }
- }
|