This commit is contained in:
John Guo
2025-03-02 22:16:48 +08:00
parent 1c1c145911
commit bd5b6a1ed7
34 changed files with 3598 additions and 2454 deletions

View File

@ -39,7 +39,7 @@ var (
// RegisterConverter registers custom converter.
// Deprecated: use RegisterTypeConverterFunc instead for clear
func RegisterConverter(fn any) (err error) {
return defaultConverter.RegisterTypeConverterFunc(fn)
return RegisterTypeConverterFunc(fn)
}
// RegisterTypeConverterFunc registers custom converter.

View File

@ -15,7 +15,7 @@ import (
// 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 any, toTypeName string, extraParams ...any) any {
return defaultConverter.doConvert(
result, _ := defaultConverter.doConvert(
doConvertInput{
FromValue: fromValue,
ToTypeName: toTypeName,
@ -23,6 +23,7 @@ func Convert(fromValue any, toTypeName string, extraParams ...any) any {
Extra: extraParams,
},
)
return result
}
// ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`.
@ -36,12 +37,11 @@ func ConvertWithRefer(fromValue any, referValue any, extraParams ...any) any {
} else {
referValueRf = reflect.ValueOf(referValue)
}
return defaultConverter.doConvert(
doConvertInput{
FromValue: fromValue,
ToTypeName: referValueRf.Type().String(),
ReferValue: referValue,
Extra: extraParams,
},
)
result, _ := defaultConverter.doConvert(doConvertInput{
FromValue: fromValue,
ToTypeName: referValueRf.Type().String(),
ReferValue: referValue,
Extra: extraParams,
})
return result
}

View File

@ -7,14 +7,11 @@
package gconv
import (
"context"
"reflect"
"time"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv/internal/structcache"
)
@ -26,9 +23,49 @@ type (
)
// Converter is the manager for type converting.
type Converter struct {
internalConvertConfig *structcache.ConvertConfig
typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc
type Converter interface {
RegisterTypeConverterFunc(fn any) (err error)
ConverterForInt
ConverterForUint
String(any any) (string, error)
Bool(any any) (bool, error)
Bytes(any any) ([]byte, error)
Float32(any any) (float32, error)
Float64(any any) (float64, error)
doMapConvert(
value any, recursive recursiveType, mustMapReturn bool, option ...MapOption,
) map[string]any
MapToMap(params any, pointer any, mapping ...map[string]string) (err error)
MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error)
Rune(any any) (rune, error)
Runes(any any) ([]rune, error)
Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error)
Time(any interface{}, format ...string) (time.Time, error)
Duration(any interface{}) (time.Duration, error)
GTime(any interface{}, format ...string) (*gtime.Time, error)
}
type ConverterForInt interface {
Int(any any) (int, error)
Int8(any any) (int8, error)
Int16(any any) (int16, error)
Int32(any any) (int32, error)
Int64(any any) (int64, error)
}
type ConverterForUint interface {
Uint(any any) (uint, error)
Uint8(any any) (uint8, error)
Uin16(any any) (uint16, error)
Uint32(any any) (uint32, error)
Uint64(any any) (uint64, error)
}
// impConverter implements the interface Converter.
type impConverter struct {
internalConverter *structcache.Converter
typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc
}
var (
@ -57,48 +94,15 @@ var (
)
// NewConverter creates and returns management object for type converting.
func NewConverter() *Converter {
cf := &Converter{
internalConvertConfig: structcache.NewConvertConfig(),
typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc),
func NewConverter() *impConverter {
cf := &impConverter{
internalConverter: structcache.NewConverter(),
typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc),
}
cf.registerBuiltInConverter()
return cf
}
func (c *Converter) registerBuiltInConverter() {
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForString, stringType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForFloat64, float32Type, float64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForBool, boolType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForBytes, bytesType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForTime, timeType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForGTime, gtimeType,
)
}
func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) {
for _, t := range types {
c.internalConvertConfig.RegisterAnyConvertFunc(t, convertFunc)
}
}
// RegisterTypeConverterFunc registers custom converter.
// It must be registered before you use this custom converting feature.
// It is suggested to do it in boot procedure of the process.
@ -107,7 +111,7 @@ func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, t
// 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`.
// It will convert type `T1` to type `T2`.
// 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer.
func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) {
func (c *impConverter) RegisterTypeConverterFunc(fn any) (err error) {
var (
fnReflectType = reflect.TypeOf(fn)
errType = reflect.TypeOf((*error)(nil)).Elem()
@ -160,418 +164,39 @@ func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) {
return
}
registeredOutTypeMap[outType] = reflect.ValueOf(fn)
c.internalConvertConfig.RegisterTypeConvertFunc(outType)
c.internalConverter.RegisterTypeConvertFunc(outType)
return
}
func (c *Converter) getRegisteredConverterFuncAndSrcType(
srcReflectValue, dstReflectValueForRefer reflect.Value,
) (f converterFunc, srcType reflect.Type, ok bool) {
if len(c.typeConverterFuncMap) == 0 {
return reflect.Value{}, nil, false
}
srcType = srcReflectValue.Type()
for srcType.Kind() == reflect.Pointer {
srcType = srcType.Elem()
}
var registeredOutTypeMap map[converterOutType]converterFunc
// firstly, it searches the map by input parameter type.
registeredOutTypeMap, ok = c.typeConverterFuncMap[srcType]
if !ok {
return reflect.Value{}, nil, false
}
var dstType = dstReflectValueForRefer.Type()
if dstType.Kind() == reflect.Pointer {
// Might be **struct, which is support as designed.
if dstType.Elem().Kind() == reflect.Pointer {
dstType = dstType.Elem()
}
} else if dstReflectValueForRefer.IsValid() && dstReflectValueForRefer.CanAddr() {
dstType = dstReflectValueForRefer.Addr().Type()
} else {
dstType = reflect.PointerTo(dstType)
}
// secondly, it searches the input parameter type map
// and finds the result converter function by the output parameter type.
f, ok = registeredOutTypeMap[dstType]
if !ok {
return reflect.Value{}, nil, false
}
return
func (c *impConverter) registerBuiltInConverter() {
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForString, stringType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForFloat64, float32Type, float64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForBool, boolType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForBytes, bytesType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForTime, timeType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForGTime, gtimeType,
)
}
func (c *Converter) callCustomConverterWithRefer(
srcReflectValue, referReflectValue reflect.Value,
) (dstReflectValue reflect.Value, converted bool, err error) {
registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue)
if !ok {
return reflect.Value{}, false, nil
}
dstReflectValue = reflect.New(referReflectValue.Type()).Elem()
converted, err = c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)
return
}
// callCustomConverter call the custom converter. It will try some possible type.
func (c *Converter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) {
registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue)
if !ok {
return false, nil
}
return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)
}
func (c *Converter) doCallCustomConverter(
srcReflectValue reflect.Value,
dstReflectValue reflect.Value,
registeredConverterFunc converterFunc,
srcType reflect.Type,
) (converted bool, err error) {
// Converter function calling.
for srcReflectValue.Type() != srcType {
srcReflectValue = srcReflectValue.Elem()
}
result := registeredConverterFunc.Call([]reflect.Value{srcReflectValue})
if !result[1].IsNil() {
return false, result[1].Interface().(error)
}
// The `result[0]` is a pointer.
if result[0].IsNil() {
return false, nil
}
var resultValue = result[0]
for {
if resultValue.Type() == dstReflectValue.Type() && dstReflectValue.CanSet() {
dstReflectValue.Set(resultValue)
converted = true
} else if dstReflectValue.Kind() == reflect.Pointer {
if resultValue.Type() == dstReflectValue.Elem().Type() && dstReflectValue.Elem().CanSet() {
dstReflectValue.Elem().Set(resultValue)
converted = true
}
}
if converted {
break
}
if resultValue.Kind() == reflect.Pointer {
resultValue = resultValue.Elem()
} else {
break
}
}
return converted, nil
}
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 (c *Converter) 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":
// issue 3449
bytes, err := json.Marshal(in.FromValue)
if err != nil {
intlog.Errorf(context.TODO(), `%+v`, err)
}
return bytes
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)
}
var fromReflectValue reflect.Value
if v, ok := in.FromValue.(reflect.Value); ok {
fromReflectValue = v
} else {
fromReflectValue = reflect.ValueOf(in.FromValue)
}
// custom converter.
if dstReflectValue, ok, _ := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue); ok {
return dstReflectValue.Interface()
}
defer func() {
if recover() != nil {
in.alreadySetToReferValue = false
if err := c.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(c.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 := c.MapToMap(in.FromValue, targetValue); err == nil {
in.alreadySetToReferValue = true
}
return targetValue.Interface()
default:
}
in.ToTypeName = referReflectValue.Kind().String()
in.ReferValue = nil
in.alreadySetToReferValue = true
convertedValue = reflect.ValueOf(c.doConvert(in)).Convert(referReflectValue.Type()).Interface()
return convertedValue
}
return in.FromValue
}
}
func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) {
convertedValue := c.doConvert(in)
if !in.alreadySetToReferValue {
reflectValue.Set(reflect.ValueOf(convertedValue))
func (c *impConverter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) {
for _, t := range types {
c.internalConverter.RegisterAnyConvertFunc(t, convertFunc)
}
}

View File

@ -14,7 +14,8 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *Converter) Bool(any any) (bool, error) {
// Bool converts `any` to bool.
func (c *impConverter) Bool(any any) (bool, error) {
if empty.IsNil(any) {
return false, nil
}

View File

@ -13,7 +13,7 @@ import (
"github.com/gogf/gf/v2/os/gtime"
)
func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error {
func (c *impConverter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error {
v, err := c.Int64(from)
if err != nil {
return err
@ -22,7 +22,7 @@ func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) er
return nil
}
func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error {
func (c *impConverter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error {
v, err := c.Uint64(from)
if err != nil {
return err
@ -31,7 +31,7 @@ func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) e
return nil
}
func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) error {
func (c *impConverter) builtInAnyConvertFuncForString(from any, to reflect.Value) error {
v, err := c.String(from)
if err != nil {
return err
@ -40,7 +40,7 @@ func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) e
return nil
}
func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error {
func (c *impConverter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error {
v, err := c.Float64(from)
if err != nil {
return err
@ -49,7 +49,7 @@ func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value)
return nil
}
func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error {
func (c *impConverter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error {
v, err := c.Bool(from)
if err != nil {
return err
@ -58,7 +58,7 @@ func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) err
return nil
}
func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error {
func (c *impConverter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error {
v, err := c.Bytes(from)
if err != nil {
return err
@ -67,7 +67,7 @@ func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) er
return nil
}
func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error {
func (c *impConverter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error {
t, err := c.Time(from)
if err != nil {
return err
@ -76,7 +76,7 @@ func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) err
return nil
}
func (c *Converter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error {
func (c *impConverter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error {
v, err := c.GTime(from)
if err != nil {
return err

View File

@ -17,7 +17,7 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *Converter) Bytes(any any) ([]byte, error) {
func (c *impConverter) Bytes(any any) ([]byte, error) {
if empty.IsNil(any) {
return nil, nil
}

View File

@ -0,0 +1,522 @@
// 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/internal/json"
"github.com/gogf/gf/v2/os/gtime"
)
type doConvertInput struct {
FromValue any // Value that is converted from.
ToTypeName string // Target value type name in string.
ReferValue any // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value.
Extra []any // 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 (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err error) {
switch in.ToTypeName {
case "int":
return c.Int(in.FromValue)
case "*int":
if _, ok := in.FromValue.(*int); ok {
return in.FromValue, nil
}
v, err := c.Int(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "int8":
return c.Int8(in.FromValue)
case "*int8":
if _, ok := in.FromValue.(*int8); ok {
return in.FromValue, nil
}
v, err := c.Int8(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "int16":
return c.Int16(in.FromValue)
case "*int16":
if _, ok := in.FromValue.(*int16); ok {
return in.FromValue, nil
}
v, err := c.Int16(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "int32":
return c.Int32(in.FromValue)
case "*int32":
if _, ok := in.FromValue.(*int32); ok {
return in.FromValue, nil
}
v, err := c.Int32(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "int64":
return c.Int64(in.FromValue)
case "*int64":
if _, ok := in.FromValue.(*int64); ok {
return in.FromValue, nil
}
v, err := c.Int64(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "uint":
return c.Uint(in.FromValue)
case "*uint":
if _, ok := in.FromValue.(*uint); ok {
return in.FromValue, nil
}
v, err := c.Uint(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "uint8":
return c.Uint8(in.FromValue)
case "*uint8":
if _, ok := in.FromValue.(*uint8); ok {
return in.FromValue, nil
}
v, err := c.Uint8(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "uint16":
return c.Uint16(in.FromValue)
case "*uint16":
if _, ok := in.FromValue.(*uint16); ok {
return in.FromValue, nil
}
v, err := c.Uint16(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "uint32":
return c.Uint32(in.FromValue)
case "*uint32":
if _, ok := in.FromValue.(*uint32); ok {
return in.FromValue, nil
}
v, err := c.Uint32(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "uint64":
return c.Uint64(in.FromValue)
case "*uint64":
if _, ok := in.FromValue.(*uint64); ok {
return in.FromValue, nil
}
v, err := c.Uint64(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "float32":
return c.Float32(in.FromValue)
case "*float32":
if _, ok := in.FromValue.(*float32); ok {
return in.FromValue, nil
}
v, err := c.Float32(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "float64":
return c.Float64(in.FromValue)
case "*float64":
if _, ok := in.FromValue.(*float64); ok {
return in.FromValue, nil
}
v, err := c.Float64(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "bool":
return c.Bool(in.FromValue)
case "*bool":
if _, ok := in.FromValue.(*bool); ok {
return in.FromValue, nil
}
v, err := c.Bool(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "string":
return c.String(in.FromValue)
case "*string":
if _, ok := in.FromValue.(*string); ok {
return in.FromValue, nil
}
v, err := c.String(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "[]byte":
return c.Bytes(in.FromValue)
case "[]int":
return c.SliceInt(in.FromValue, SliceOption{})
case "[]int32":
return c.SliceInt32(in.FromValue, SliceOption{})
case "[]int64":
return c.SliceInt64(in.FromValue, SliceOption{})
case "[]uint":
return c.SliceUint(in.FromValue, SliceOption{})
case "[]uint8":
return c.Bytes(in.FromValue)
case "[]uint32":
return c.SliceUint32(in.FromValue, SliceOption{})
case "[]uint64":
return c.SliceUint64(in.FromValue, SliceOption{})
case "[]float32":
return c.SliceFloat32(in.FromValue, SliceOption{})
case "[]float64":
return c.SliceFloat64(in.FromValue, SliceOption{})
case "[]string":
return c.SliceStr(in.FromValue, SliceOption{})
case "Time", "time.Time":
if len(in.Extra) > 0 {
s, err := c.String(in.Extra[0])
if err != nil {
return nil, err
}
return c.Time(in.FromValue, s)
}
return c.Time(in.FromValue)
case "*time.Time":
var v time.Time
if len(in.Extra) > 0 {
s, err := c.String(in.Extra[0])
if err != nil {
return time.Time{}, err
}
v, err = c.Time(in.FromValue, s)
if err != nil {
return time.Time{}, err
}
} else {
if _, ok := in.FromValue.(*time.Time); ok {
return in.FromValue, nil
}
v, err = c.Time(in.FromValue)
if err != nil {
return time.Time{}, err
}
}
return &v, nil
case "GTime", "gtime.Time":
if len(in.Extra) > 0 {
s, err := c.String(in.Extra[0])
if err != nil {
return *gtime.New(), err
}
v, err := c.GTime(in.FromValue, s)
if err != nil {
return *gtime.New(), err
}
if v != nil {
return *v, nil
}
return *gtime.New(), nil
}
v, err := c.GTime(in.FromValue)
if err != nil {
return *gtime.New(), err
}
if v != nil {
return *v, nil
}
return *gtime.New(), nil
case "*gtime.Time":
if len(in.Extra) > 0 {
s, err := c.String(in.Extra[0])
if err != nil {
return gtime.New(), err
}
v, err := c.GTime(in.FromValue, s)
if err != nil {
return gtime.New(), err
}
if v != nil {
return v, nil
}
return gtime.New(), nil
}
v, err := c.GTime(in.FromValue)
if err != nil {
return gtime.New(), err
}
if v != nil {
return v, nil
}
return gtime.New(), nil
case "Duration", "time.Duration":
return c.Duration(in.FromValue)
case "*time.Duration":
if _, ok := in.FromValue.(*time.Duration); ok {
return in.FromValue, nil
}
v, err := c.Duration(in.FromValue)
if err != nil {
return nil, err
}
return &v, nil
case "map[string]string":
return MapStrStr(in.FromValue), nil
case "map[string]interface {}":
return Map(in.FromValue, MapOption{}), nil
case "[]map[string]interface {}":
return c.SliceMap(in.FromValue, SliceOption{}, MapOption{})
case "RawMessage", "json.RawMessage":
// issue 3449
bytes, err := json.Marshal(in.FromValue)
if err != nil {
return nil, err
}
return bytes, nil
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)
}
var fromReflectValue reflect.Value
if v, ok := in.FromValue.(reflect.Value); ok {
fromReflectValue = v
} else {
fromReflectValue = reflect.ValueOf(in.FromValue)
}
// custom converter.
dstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue)
if err != nil {
return nil, err
}
if ok {
return dstReflectValue.Interface(), nil
}
defer func() {
if recover() != nil {
in.alreadySetToReferValue = false
if err := c.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
result, err := c.doConvert(in)
if err != nil {
return nil, err
}
refElementValue := reflect.ValueOf(result)
originTypeValue := reflect.New(refElementValue.Type()).Elem()
originTypeValue.Set(refElementValue)
in.alreadySetToReferValue = true
return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface(), nil
}
case reflect.Map:
var targetValue = reflect.New(referReflectValue.Type()).Elem()
if err = c.MapToMap(in.FromValue, targetValue); err == nil {
in.alreadySetToReferValue = true
}
return targetValue.Interface(), nil
default:
}
in.ToTypeName = referReflectValue.Kind().String()
in.ReferValue = nil
in.alreadySetToReferValue = true
result, err := c.doConvert(in)
if err != nil {
return nil, err
}
convertedValue = reflect.ValueOf(result).Convert(referReflectValue.Type()).Interface()
return convertedValue, nil
}
return in.FromValue, nil
}
}
func (c *impConverter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) error {
convertedValue, err := c.doConvert(in)
if err != nil {
return err
}
if !in.alreadySetToReferValue {
reflectValue.Set(reflect.ValueOf(convertedValue))
}
return err
}
func (c *impConverter) getRegisteredConverterFuncAndSrcType(
srcReflectValue, dstReflectValueForRefer reflect.Value,
) (f converterFunc, srcType reflect.Type, ok bool) {
if len(c.typeConverterFuncMap) == 0 {
return reflect.Value{}, nil, false
}
srcType = srcReflectValue.Type()
for srcType.Kind() == reflect.Pointer {
srcType = srcType.Elem()
}
var registeredOutTypeMap map[converterOutType]converterFunc
// firstly, it searches the map by input parameter type.
registeredOutTypeMap, ok = c.typeConverterFuncMap[srcType]
if !ok {
return reflect.Value{}, nil, false
}
var dstType = dstReflectValueForRefer.Type()
if dstType.Kind() == reflect.Pointer {
// Might be **struct, which is support as designed.
if dstType.Elem().Kind() == reflect.Pointer {
dstType = dstType.Elem()
}
} else if dstReflectValueForRefer.IsValid() && dstReflectValueForRefer.CanAddr() {
dstType = dstReflectValueForRefer.Addr().Type()
} else {
dstType = reflect.PointerTo(dstType)
}
// secondly, it searches the input parameter type map
// and finds the result converter function by the output parameter type.
f, ok = registeredOutTypeMap[dstType]
if !ok {
return reflect.Value{}, nil, false
}
return
}
func (c *impConverter) callCustomConverterWithRefer(
srcReflectValue, referReflectValue reflect.Value,
) (dstReflectValue reflect.Value, converted bool, err error) {
registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue)
if !ok {
return reflect.Value{}, false, nil
}
dstReflectValue = reflect.New(referReflectValue.Type()).Elem()
converted, err = c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)
return
}
// callCustomConverter call the custom converter. It will try some possible type.
func (c *impConverter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) {
registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue)
if !ok {
return false, nil
}
return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)
}
func (c *impConverter) doCallCustomConverter(
srcReflectValue reflect.Value,
dstReflectValue reflect.Value,
registeredConverterFunc converterFunc,
srcType reflect.Type,
) (converted bool, err error) {
// Converter function calling.
for srcReflectValue.Type() != srcType {
srcReflectValue = srcReflectValue.Elem()
}
result := registeredConverterFunc.Call([]reflect.Value{srcReflectValue})
if !result[1].IsNil() {
return false, result[1].Interface().(error)
}
// The `result[0]` is a pointer.
if result[0].IsNil() {
return false, nil
}
var resultValue = result[0]
for {
if resultValue.Type() == dstReflectValue.Type() && dstReflectValue.CanSet() {
dstReflectValue.Set(resultValue)
converted = true
} else if dstReflectValue.Kind() == reflect.Pointer {
if resultValue.Type() == dstReflectValue.Elem().Type() && dstReflectValue.Elem().CanSet() {
dstReflectValue.Elem().Set(resultValue)
converted = true
}
}
if converted {
break
}
if resultValue.Kind() == reflect.Pointer {
resultValue = resultValue.Elem()
} else {
break
}
}
return converted, nil
}

View File

@ -0,0 +1,504 @@
// 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"
"strings"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
"github.com/gogf/gf/v2/util/gtag"
)
// MapConvert implements the map converting.
// It automatically checks and converts json string to map if `value` is string/[]byte.
//
// TODO completely implement the recursive converting for all types, especially the map.
func (c *impConverter) doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} {
if value == nil {
return nil
}
// It redirects to its underlying value if it has implemented interface iVal.
if v, ok := value.(localinterface.IVal); ok {
value = v.Val()
}
var (
usedOption = getUsedMapOption(option...)
newTags = gtag.StructTagPriority
)
if usedOption.Deep {
recursive = recursiveTypeTrue
}
switch len(usedOption.Tags) {
case 0:
// No need handling.
case 1:
newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...)
default:
newTags = append(usedOption.Tags, gtag.StructTagPriority...)
}
// Assert the common combination of types, and finally it uses reflection.
dataMap := make(map[string]interface{})
switch r := value.(type) {
case string:
// If it is a JSON string, automatically unmarshal it!
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil {
return nil
}
} else {
return nil
}
case []byte:
// If it is a JSON string, automatically unmarshal it!
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
if err := json.UnmarshalUseNumber(r, &dataMap); err != nil {
return nil
}
} else {
return nil
}
case map[interface{}]interface{}:
recursiveOption := usedOption
recursiveOption.Tags = newTags
for k, v := range r {
dataMap[String(k)] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: v,
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Option: recursiveOption,
},
)
}
case map[interface{}]string:
for k, v := range r {
dataMap[String(k)] = v
}
case map[interface{}]int:
for k, v := range r {
dataMap[String(k)] = v
}
case map[interface{}]uint:
for k, v := range r {
dataMap[String(k)] = v
}
case map[interface{}]float32:
for k, v := range r {
dataMap[String(k)] = v
}
case map[interface{}]float64:
for k, v := range r {
dataMap[String(k)] = v
}
case map[string]bool:
for k, v := range r {
dataMap[k] = v
}
case map[string]int:
for k, v := range r {
dataMap[k] = v
}
case map[string]uint:
for k, v := range r {
dataMap[k] = v
}
case map[string]float32:
for k, v := range r {
dataMap[k] = v
}
case map[string]float64:
for k, v := range r {
dataMap[k] = v
}
case map[string]string:
for k, v := range r {
dataMap[k] = v
}
case map[string]interface{}:
if recursive == recursiveTypeTrue {
recursiveOption := usedOption
recursiveOption.Tags = newTags
// A copy of current map.
for k, v := range r {
dataMap[k] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: v,
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Option: recursiveOption,
},
)
}
} else {
// It returns the map directly without any changing.
return r
}
case map[int]interface{}:
recursiveOption := usedOption
recursiveOption.Tags = newTags
for k, v := range r {
dataMap[String(k)] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: v,
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Option: recursiveOption,
},
)
}
case map[int]string:
for k, v := range r {
dataMap[String(k)] = v
}
case map[uint]string:
for k, v := range r {
dataMap[String(k)] = v
}
default:
// Not a common type, it then uses reflection for conversion.
var reflectValue reflect.Value
if v, ok := value.(reflect.Value); ok {
reflectValue = v
} else {
reflectValue = reflect.ValueOf(value)
}
reflectKind := reflectValue.Kind()
// If it is a pointer, we should find its real data type.
for reflectKind == reflect.Ptr {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
}
switch reflectKind {
// If `value` is type of array, it converts the value of even number index as its key and
// the value of odd number index as its corresponding value, for example:
// []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"}
// []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil}
case reflect.Slice, reflect.Array:
length := reflectValue.Len()
for i := 0; i < length; i += 2 {
if i+1 < length {
dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface()
} else {
dataMap[String(reflectValue.Index(i).Interface())] = nil
}
}
case reflect.Map, reflect.Struct, reflect.Interface:
recursiveOption := usedOption
recursiveOption.Tags = newTags
convertedValue := c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: true,
Value: value,
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Option: recursiveOption,
MustMapReturn: mustMapReturn,
},
)
if m, ok := convertedValue.(map[string]interface{}); ok {
return m
}
return nil
default:
return nil
}
}
return dataMap
}
func getUsedMapOption(option ...MapOption) MapOption {
var usedOption MapOption
if len(option) > 0 {
usedOption = option[0]
}
return usedOption
}
type doMapConvertForMapOrStructValueInput struct {
IsRoot bool // It returns directly if it is not root and with no recursive converting.
Value interface{} // Current operation value.
RecursiveType recursiveType // The type from top function entry.
RecursiveOption bool // Whether convert recursively for `current` operation.
Option MapOption // Map converting option.
MustMapReturn bool // Must return map instead of Value when empty.
}
func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} {
if !in.IsRoot && !in.RecursiveOption {
return in.Value
}
var reflectValue reflect.Value
if v, ok := in.Value.(reflect.Value); ok {
reflectValue = v
in.Value = v.Interface()
} else {
reflectValue = reflect.ValueOf(in.Value)
}
reflectKind := reflectValue.Kind()
// If it is a pointer, we should find its real data type.
for reflectKind == reflect.Ptr {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
}
switch reflectKind {
case reflect.Map:
var (
mapIter = reflectValue.MapRange()
dataMap = make(map[string]interface{})
)
for mapIter.Next() {
var (
mapKeyValue = mapIter.Value()
mapValue interface{}
)
switch {
case mapKeyValue.IsZero():
if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() {
// quick check for nil value.
mapValue = nil
} else {
// in case of:
// exception recovered: reflect: call of reflect.Value.Interface on zero Value
mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface()
}
default:
mapValue = mapKeyValue.Interface()
}
dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: mapValue,
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
},
)
}
return dataMap
case reflect.Struct:
var dataMap = make(map[string]interface{})
// Map converting interface check.
if v, ok := in.Value.(localinterface.IMapStrAny); ok {
// Value copy, in case of concurrent safety.
for mapK, mapV := range v.MapStrAny() {
if in.RecursiveOption {
dataMap[mapK] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: mapV,
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
},
)
} else {
dataMap[mapK] = mapV
}
}
if len(dataMap) > 0 {
return dataMap
}
}
// Using reflect for converting.
var (
rtField reflect.StructField
rvField reflect.Value
reflectType = reflectValue.Type() // attribute value type.
mapKey = "" // mapKey may be the tag name or the struct attribute name.
)
for i := 0; i < reflectValue.NumField(); i++ {
rtField = reflectType.Field(i)
rvField = reflectValue.Field(i)
// Only convert the public attributes.
fieldName := rtField.Name
if !utils.IsLetterUpper(fieldName[0]) {
continue
}
mapKey = ""
fieldTag := rtField.Tag
for _, tag := range in.Option.Tags {
if mapKey = fieldTag.Get(tag); mapKey != "" {
break
}
}
if mapKey == "" {
mapKey = fieldName
} else {
// Support json tag feature: -, omitempty
mapKey = strings.TrimSpace(mapKey)
if mapKey == "-" {
continue
}
array := strings.Split(mapKey, ",")
if len(array) > 1 {
switch strings.TrimSpace(array[1]) {
case "omitempty":
if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) {
continue
} else {
mapKey = strings.TrimSpace(array[0])
}
default:
mapKey = strings.TrimSpace(array[0])
}
}
if mapKey == "" {
mapKey = fieldName
}
}
if in.RecursiveOption || rtField.Anonymous {
// Do map converting recursively.
var (
rvAttrField = rvField
rvAttrKind = rvField.Kind()
)
if rvAttrKind == reflect.Ptr {
rvAttrField = rvField.Elem()
rvAttrKind = rvAttrField.Kind()
}
switch rvAttrKind {
case reflect.Struct:
// Embedded struct and has no fields, just ignores it.
// Eg: gmeta.Meta
if rvAttrField.Type().NumField() == 0 {
continue
}
var (
hasNoTag = mapKey == fieldName
// DO NOT use rvAttrField.Interface() here,
// as it might be changed from pointer to struct.
rvInterface = rvField.Interface()
)
switch {
case hasNoTag && rtField.Anonymous:
// It means this attribute field has no tag.
// Overwrite the attribute with sub-struct attribute fields.
anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: rvInterface,
RecursiveType: in.RecursiveType,
RecursiveOption: true,
Option: in.Option,
})
if m, ok := anonymousValue.(map[string]interface{}); ok {
for k, v := range m {
dataMap[k] = v
}
} else {
dataMap[mapKey] = rvInterface
}
// It means this attribute field has desired tag.
case !hasNoTag && rtField.Anonymous:
dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: rvInterface,
RecursiveType: in.RecursiveType,
RecursiveOption: true,
Option: in.Option,
})
default:
dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: rvInterface,
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
})
}
// The struct attribute is type of slice.
case reflect.Array, reflect.Slice:
length := rvAttrField.Len()
if length == 0 {
dataMap[mapKey] = rvAttrField.Interface()
break
}
array := make([]interface{}, length)
for arrayIndex := 0; arrayIndex < length; arrayIndex++ {
array[arrayIndex] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: rvAttrField.Index(arrayIndex).Interface(),
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
},
)
}
dataMap[mapKey] = array
case reflect.Map:
var (
mapIter = rvAttrField.MapRange()
nestedMap = make(map[string]interface{})
)
for mapIter.Next() {
nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: mapIter.Value().Interface(),
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
},
)
}
dataMap[mapKey] = nestedMap
default:
if rvField.IsValid() {
dataMap[mapKey] = reflectValue.Field(i).Interface()
} else {
dataMap[mapKey] = nil
}
}
} else {
// No recursive map value converting
if rvField.IsValid() {
dataMap[mapKey] = reflectValue.Field(i).Interface()
} else {
dataMap[mapKey] = nil
}
}
}
if !in.MustMapReturn && len(dataMap) == 0 {
return in.Value
}
return dataMap
// The given value is type of slice.
case reflect.Array, reflect.Slice:
length := reflectValue.Len()
if length == 0 {
break
}
array := make([]interface{}, reflectValue.Len())
for i := 0; i < length; i++ {
array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: reflectValue.Index(i).Interface(),
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
})
}
return array
default:
}
return in.Value
}

View File

@ -17,7 +17,7 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *Converter) Float32(any any) (float32, error) {
func (c *impConverter) Float32(any any) (float32, error) {
if empty.IsNil(any) {
return 0, nil
}
@ -78,7 +78,7 @@ func (c *Converter) Float32(any any) (float32, error) {
}
}
func (c *Converter) Float64(any any) (float64, error) {
func (c *impConverter) Float64(any any) (float64, error) {
if empty.IsNil(any) {
return 0, nil
}

View File

@ -18,7 +18,7 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *Converter) Int(any any) (int, error) {
func (c *impConverter) Int(any any) (int, error) {
if v, ok := any.(int); ok {
return v, nil
}
@ -29,7 +29,7 @@ func (c *Converter) Int(any any) (int, error) {
return int(v), nil
}
func (c *Converter) Int8(any any) (int8, error) {
func (c *impConverter) Int8(any any) (int8, error) {
if v, ok := any.(int8); ok {
return v, nil
}
@ -40,7 +40,7 @@ func (c *Converter) Int8(any any) (int8, error) {
return int8(v), nil
}
func (c *Converter) Int16(any any) (int16, error) {
func (c *impConverter) Int16(any any) (int16, error) {
if v, ok := any.(int16); ok {
return v, nil
}
@ -51,7 +51,7 @@ func (c *Converter) Int16(any any) (int16, error) {
return int16(v), nil
}
func (c *Converter) Int32(any any) (int32, error) {
func (c *impConverter) Int32(any any) (int32, error) {
if v, ok := any.(int32); ok {
return v, nil
}
@ -62,7 +62,7 @@ func (c *Converter) Int32(any any) (int32, error) {
return int32(v), nil
}
func (c *Converter) Int64(any any) (int64, error) {
func (c *impConverter) Int64(any any) (int64, error) {
if empty.IsNil(any) {
return 0, nil
}

View File

@ -6,499 +6,492 @@
package gconv
import (
"reflect"
"strings"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
"github.com/gogf/gf/v2/util/gtag"
)
// MapConvert implements the map converting.
// It automatically checks and converts json string to map if `value` is string/[]byte.
//// MapStrStr converts `value` to map[string]string.
//// Note that there might be data copy for this map type converting.
//func (c *impConverter) MapStrStr(value any, option ...MapOption) (map[string]string, error) {
// if r, ok := value.(map[string]string); ok {
// return r, nil
// }
// m := Map(value, option...)
// if len(m) > 0 {
// vMap := make(map[string]string, len(m))
// for k, v := range m {
// s, err := c.String(v)
// if err != nil {
// return nil, err
// }
// vMap[k] = s
// }
// return vMap, nil
// }
// return nil, nil
//}
//
// TODO completely implement the recursive converting for all types, especially the map.
func (c *Converter) doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} {
if value == nil {
return nil
}
// It redirects to its underlying value if it has implemented interface iVal.
if v, ok := value.(localinterface.IVal); ok {
value = v.Val()
}
var (
usedOption = getUsedMapOption(option...)
newTags = gtag.StructTagPriority
)
if usedOption.Deep {
recursive = recursiveTypeTrue
}
switch len(usedOption.Tags) {
case 0:
// No need handling.
case 1:
newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...)
default:
newTags = append(usedOption.Tags, gtag.StructTagPriority...)
}
// Assert the common combination of types, and finally it uses reflection.
dataMap := make(map[string]interface{})
switch r := value.(type) {
case string:
// If it is a JSON string, automatically unmarshal it!
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil {
return nil
}
} else {
return nil
}
case []byte:
// If it is a JSON string, automatically unmarshal it!
if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
if err := json.UnmarshalUseNumber(r, &dataMap); err != nil {
return nil
}
} else {
return nil
}
case map[interface{}]interface{}:
recursiveOption := usedOption
recursiveOption.Tags = newTags
for k, v := range r {
dataMap[String(k)] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: v,
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Option: recursiveOption,
},
)
}
case map[interface{}]string:
for k, v := range r {
dataMap[String(k)] = v
}
case map[interface{}]int:
for k, v := range r {
dataMap[String(k)] = v
}
case map[interface{}]uint:
for k, v := range r {
dataMap[String(k)] = v
}
case map[interface{}]float32:
for k, v := range r {
dataMap[String(k)] = v
}
case map[interface{}]float64:
for k, v := range r {
dataMap[String(k)] = v
}
case map[string]bool:
for k, v := range r {
dataMap[k] = v
}
case map[string]int:
for k, v := range r {
dataMap[k] = v
}
case map[string]uint:
for k, v := range r {
dataMap[k] = v
}
case map[string]float32:
for k, v := range r {
dataMap[k] = v
}
case map[string]float64:
for k, v := range r {
dataMap[k] = v
}
case map[string]string:
for k, v := range r {
dataMap[k] = v
}
case map[string]interface{}:
if recursive == recursiveTypeTrue {
recursiveOption := usedOption
recursiveOption.Tags = newTags
// A copy of current map.
for k, v := range r {
dataMap[k] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: v,
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Option: recursiveOption,
},
)
}
} else {
// It returns the map directly without any changing.
return r
}
case map[int]interface{}:
recursiveOption := usedOption
recursiveOption.Tags = newTags
for k, v := range r {
dataMap[String(k)] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: v,
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Option: recursiveOption,
},
)
}
case map[int]string:
for k, v := range r {
dataMap[String(k)] = v
}
case map[uint]string:
for k, v := range r {
dataMap[String(k)] = v
}
default:
// Not a common type, it then uses reflection for conversion.
var reflectValue reflect.Value
if v, ok := value.(reflect.Value); ok {
reflectValue = v
} else {
reflectValue = reflect.ValueOf(value)
}
reflectKind := reflectValue.Kind()
// If it is a pointer, we should find its real data type.
for reflectKind == reflect.Ptr {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
}
switch reflectKind {
// If `value` is type of array, it converts the value of even number index as its key and
// the value of odd number index as its corresponding value, for example:
// []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"}
// []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil}
case reflect.Slice, reflect.Array:
length := reflectValue.Len()
for i := 0; i < length; i += 2 {
if i+1 < length {
dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface()
} else {
dataMap[String(reflectValue.Index(i).Interface())] = nil
}
}
case reflect.Map, reflect.Struct, reflect.Interface:
recursiveOption := usedOption
recursiveOption.Tags = newTags
convertedValue := c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: true,
Value: value,
RecursiveType: recursive,
RecursiveOption: recursive == recursiveTypeTrue,
Option: recursiveOption,
MustMapReturn: mustMapReturn,
},
)
if m, ok := convertedValue.(map[string]interface{}); ok {
return m
}
return nil
default:
return nil
}
}
return dataMap
}
func getUsedMapOption(option ...MapOption) MapOption {
var usedOption MapOption
if len(option) > 0 {
usedOption = option[0]
}
return usedOption
}
type doMapConvertForMapOrStructValueInput struct {
IsRoot bool // It returns directly if it is not root and with no recursive converting.
Value interface{} // Current operation value.
RecursiveType recursiveType // The type from top function entry.
RecursiveOption bool // Whether convert recursively for `current` operation.
Option MapOption // Map converting option.
MustMapReturn bool // Must return map instead of Value when empty.
}
func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} {
if !in.IsRoot && !in.RecursiveOption {
return in.Value
}
var reflectValue reflect.Value
if v, ok := in.Value.(reflect.Value); ok {
reflectValue = v
in.Value = v.Interface()
} else {
reflectValue = reflect.ValueOf(in.Value)
}
reflectKind := reflectValue.Kind()
// If it is a pointer, we should find its real data type.
for reflectKind == reflect.Ptr {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
}
switch reflectKind {
case reflect.Map:
var (
mapIter = reflectValue.MapRange()
dataMap = make(map[string]interface{})
)
for mapIter.Next() {
var (
mapKeyValue = mapIter.Value()
mapValue interface{}
)
switch {
case mapKeyValue.IsZero():
if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() {
// quick check for nil value.
mapValue = nil
} else {
// in case of:
// exception recovered: reflect: call of reflect.Value.Interface on zero Value
mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface()
}
default:
mapValue = mapKeyValue.Interface()
}
dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: mapValue,
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
},
)
}
return dataMap
case reflect.Struct:
var dataMap = make(map[string]interface{})
// Map converting interface check.
if v, ok := in.Value.(localinterface.IMapStrAny); ok {
// Value copy, in case of concurrent safety.
for mapK, mapV := range v.MapStrAny() {
if in.RecursiveOption {
dataMap[mapK] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: mapV,
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
},
)
} else {
dataMap[mapK] = mapV
}
}
if len(dataMap) > 0 {
return dataMap
}
}
// Using reflect for converting.
var (
rtField reflect.StructField
rvField reflect.Value
reflectType = reflectValue.Type() // attribute value type.
mapKey = "" // mapKey may be the tag name or the struct attribute name.
)
for i := 0; i < reflectValue.NumField(); i++ {
rtField = reflectType.Field(i)
rvField = reflectValue.Field(i)
// Only convert the public attributes.
fieldName := rtField.Name
if !utils.IsLetterUpper(fieldName[0]) {
continue
}
mapKey = ""
fieldTag := rtField.Tag
for _, tag := range in.Option.Tags {
if mapKey = fieldTag.Get(tag); mapKey != "" {
break
}
}
if mapKey == "" {
mapKey = fieldName
} else {
// Support json tag feature: -, omitempty
mapKey = strings.TrimSpace(mapKey)
if mapKey == "-" {
continue
}
array := strings.Split(mapKey, ",")
if len(array) > 1 {
switch strings.TrimSpace(array[1]) {
case "omitempty":
if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) {
continue
} else {
mapKey = strings.TrimSpace(array[0])
}
default:
mapKey = strings.TrimSpace(array[0])
}
}
if mapKey == "" {
mapKey = fieldName
}
}
if in.RecursiveOption || rtField.Anonymous {
// Do map converting recursively.
var (
rvAttrField = rvField
rvAttrKind = rvField.Kind()
)
if rvAttrKind == reflect.Ptr {
rvAttrField = rvField.Elem()
rvAttrKind = rvAttrField.Kind()
}
switch rvAttrKind {
case reflect.Struct:
// Embedded struct and has no fields, just ignores it.
// Eg: gmeta.Meta
if rvAttrField.Type().NumField() == 0 {
continue
}
var (
hasNoTag = mapKey == fieldName
// DO NOT use rvAttrField.Interface() here,
// as it might be changed from pointer to struct.
rvInterface = rvField.Interface()
)
switch {
case hasNoTag && rtField.Anonymous:
// It means this attribute field has no tag.
// Overwrite the attribute with sub-struct attribute fields.
anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: rvInterface,
RecursiveType: in.RecursiveType,
RecursiveOption: true,
Option: in.Option,
})
if m, ok := anonymousValue.(map[string]interface{}); ok {
for k, v := range m {
dataMap[k] = v
}
} else {
dataMap[mapKey] = rvInterface
}
// It means this attribute field has desired tag.
case !hasNoTag && rtField.Anonymous:
dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: rvInterface,
RecursiveType: in.RecursiveType,
RecursiveOption: true,
Option: in.Option,
})
default:
dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: rvInterface,
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
})
}
// The struct attribute is type of slice.
case reflect.Array, reflect.Slice:
length := rvAttrField.Len()
if length == 0 {
dataMap[mapKey] = rvAttrField.Interface()
break
}
array := make([]interface{}, length)
for arrayIndex := 0; arrayIndex < length; arrayIndex++ {
array[arrayIndex] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: rvAttrField.Index(arrayIndex).Interface(),
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
},
)
}
dataMap[mapKey] = array
case reflect.Map:
var (
mapIter = rvAttrField.MapRange()
nestedMap = make(map[string]interface{})
)
for mapIter.Next() {
nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue(
doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: mapIter.Value().Interface(),
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
},
)
}
dataMap[mapKey] = nestedMap
default:
if rvField.IsValid() {
dataMap[mapKey] = reflectValue.Field(i).Interface()
} else {
dataMap[mapKey] = nil
}
}
} else {
// No recursive map value converting
if rvField.IsValid() {
dataMap[mapKey] = reflectValue.Field(i).Interface()
} else {
dataMap[mapKey] = nil
}
}
}
if !in.MustMapReturn && len(dataMap) == 0 {
return in.Value
}
return dataMap
// The given value is type of slice.
case reflect.Array, reflect.Slice:
length := reflectValue.Len()
if length == 0 {
break
}
array := make([]interface{}, reflectValue.Len())
for i := 0; i < length; i++ {
array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
IsRoot: false,
Value: reflectValue.Index(i).Interface(),
RecursiveType: in.RecursiveType,
RecursiveOption: in.RecursiveType == recursiveTypeTrue,
Option: in.Option,
})
}
return array
default:
}
return in.Value
}
//// Map implements the map converting.
//// It automatically checks and converts json string to map if `value` is string/[]byte.
////
//// TODO completely implement the recursive converting for all types, especially the map.
//func (c *impConverter) Map(value any, option MapOption) (map[string]any, error) {
// if value == nil {
// return nil, nil
// }
// // It redirects to its underlying value if it has implemented interface iVal.
// if v, ok := value.(localinterface.IVal); ok {
// value = v.Val()
// }
// var (
// newTags = gtag.StructTagPriority
// )
// switch len(option.Tags) {
// case 0:
// // No need handling.
// case 1:
// newTags = append(strings.Split(option.Tags[0], ","), gtag.StructTagPriority...)
// default:
// newTags = append(option.Tags, gtag.StructTagPriority...)
// }
// // Assert the common combination of types, and finally it uses reflection.
// dataMap := make(map[string]any)
// switch r := value.(type) {
// case string:
// // If it is a JSON string, automatically unmarshal it!
// if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
// if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil {
// return nil, err
// }
// } else {
// return nil, nil
// }
// case []byte:
// // If it is a JSON string, automatically unmarshal it!
// if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
// if err := json.UnmarshalUseNumber(r, &dataMap); err != nil {
// return nil, err
// }
// } else {
// return nil, nil
// }
// case map[any]any:
// recursiveOption := option
// recursiveOption.Tags = newTags
// for k, v := range r {
// dataMap[String(k)] = c.doMapConvertForMapOrStructValue(
// doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: v,
// Recursive: option.Deep,
// Option: recursiveOption,
// },
// )
// }
// case map[any]string:
// for k, v := range r {
// dataMap[String(k)] = v
// }
// case map[any]int:
// for k, v := range r {
// dataMap[String(k)] = v
// }
// case map[any]uint:
// for k, v := range r {
// dataMap[String(k)] = v
// }
// case map[any]float32:
// for k, v := range r {
// dataMap[String(k)] = v
// }
// case map[any]float64:
// for k, v := range r {
// dataMap[String(k)] = v
// }
// case map[string]bool:
// for k, v := range r {
// dataMap[k] = v
// }
// case map[string]int:
// for k, v := range r {
// dataMap[k] = v
// }
// case map[string]uint:
// for k, v := range r {
// dataMap[k] = v
// }
// case map[string]float32:
// for k, v := range r {
// dataMap[k] = v
// }
// case map[string]float64:
// for k, v := range r {
// dataMap[k] = v
// }
// case map[string]string:
// for k, v := range r {
// dataMap[k] = v
// }
// case map[string]any:
// if option.Deep {
// recursiveOption := option
// recursiveOption.Tags = newTags
// // A copy of current map.
// for k, v := range r {
// dataMap[k] = c.doMapConvertForMapOrStructValue(
// doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: v,
// Recursive: option.Deep,
// Option: recursiveOption,
// },
// )
// }
// } else {
// // It returns the map directly without any changing.
// return r, nil
// }
// case map[int]any:
// recursiveOption := option
// recursiveOption.Tags = newTags
// for k, v := range r {
// dataMap[String(k)] = c.doMapConvertForMapOrStructValue(
// doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: v,
// Recursive: option.Deep,
// Option: recursiveOption,
// },
// )
// }
// case map[int]string:
// for k, v := range r {
// dataMap[String(k)] = v
// }
// case map[uint]string:
// for k, v := range r {
// dataMap[String(k)] = v
// }
//
// default:
// // Not a common type, it then uses reflection for conversion.
// var reflectValue reflect.Value
// if v, ok := value.(reflect.Value); ok {
// reflectValue = v
// } else {
// reflectValue = reflect.ValueOf(value)
// }
// reflectKind := reflectValue.Kind()
// // If it is a pointer, we should find its real data type.
// for reflectKind == reflect.Ptr {
// reflectValue = reflectValue.Elem()
// reflectKind = reflectValue.Kind()
// }
// switch reflectKind {
// // If `value` is type of array, it converts the value of even number index as its key and
// // the value of odd number index as its corresponding value, for example:
// // []string{"k1","v1","k2","v2"} => map[string]any{"k1":"v1", "k2":"v2"}
// // []string{"k1","v1","k2"} => map[string]any{"k1":"v1", "k2":nil}
// case reflect.Slice, reflect.Array:
// length := reflectValue.Len()
// for i := 0; i < length; i += 2 {
// if i+1 < length {
// dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface()
// } else {
// dataMap[String(reflectValue.Index(i).Interface())] = nil
// }
// }
// case reflect.Map, reflect.Struct, reflect.Interface:
// recursiveOption := option
// recursiveOption.Tags = newTags
// convertedValue := c.doMapConvertForMapOrStructValue(
// doMapConvertForMapOrStructValueInput{
// IsRoot: true,
// Value: value,
// Recursive: option.Deep,
// Option: recursiveOption,
// MustMapReturn: option.EmptyEvenNil,
// },
// )
// if m, ok := convertedValue.(map[string]any); ok {
// return m, nil
// }
// return nil, nil
// default:
// return nil, nil
// }
// }
// return dataMap, nil
//}
//
//func getUsedMapOption(option ...MapOption) MapOption {
// var usedOption MapOption
// if len(option) > 0 {
// usedOption = option[0]
// }
// return usedOption
//}
//
//type doMapConvertForMapOrStructValueInput struct {
// IsRoot bool // It returns directly if it is not root and with no recursive converting.
// Value any // Current operation value.
// Recursive bool // Whether convert recursively for `current` operation.
// Option MapOption // Map converting option.
// MustMapReturn bool // Must return map instead of Value when empty.
//}
//
//func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) any {
// if !in.IsRoot && !in.Recursive {
// return in.Value
// }
//
// var reflectValue reflect.Value
// if v, ok := in.Value.(reflect.Value); ok {
// reflectValue = v
// in.Value = v.Interface()
// } else {
// reflectValue = reflect.ValueOf(in.Value)
// }
// reflectKind := reflectValue.Kind()
// // If it is a pointer, we should find its real data type.
// for reflectKind == reflect.Ptr {
// reflectValue = reflectValue.Elem()
// reflectKind = reflectValue.Kind()
// }
// switch reflectKind {
// case reflect.Map:
// var (
// mapIter = reflectValue.MapRange()
// dataMap = make(map[string]any)
// )
// for mapIter.Next() {
// var (
// mapKeyValue = mapIter.Value()
// mapValue any
// )
// switch {
// case mapKeyValue.IsZero():
// if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() {
// // quick check for nil value.
// mapValue = nil
// } else {
// // in case of:
// // exception recovered: reflect: call of reflect.Value.Interface on zero Value
// mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface()
// }
// default:
// mapValue = mapKeyValue.Interface()
// }
// dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue(
// doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: mapValue,
// Recursive: in.Recursive,
// Option: in.Option,
// },
// )
// }
// return dataMap
//
// case reflect.Struct:
// var dataMap = make(map[string]any)
// // Map converting interface check.
// if v, ok := in.Value.(localinterface.IMapStrAny); ok {
// // Value copy, in case of concurrent safety.
// for mapK, mapV := range v.MapStrAny() {
// if in.Recursive {
// dataMap[mapK] = c.doMapConvertForMapOrStructValue(
// doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: mapV,
// Recursive: in.Recursive,
// Option: in.Option,
// },
// )
// } else {
// dataMap[mapK] = mapV
// }
// }
// if len(dataMap) > 0 {
// return dataMap
// }
// }
// // Using reflect for converting.
// var (
// rtField reflect.StructField
// rvField reflect.Value
// reflectType = reflectValue.Type() // attribute value type.
// mapKey = "" // mapKey may be the tag name or the struct attribute name.
// )
// for i := 0; i < reflectValue.NumField(); i++ {
// rtField = reflectType.Field(i)
// rvField = reflectValue.Field(i)
// // Only convert the public attributes.
// fieldName := rtField.Name
// if !utils.IsLetterUpper(fieldName[0]) {
// continue
// }
// mapKey = ""
// fieldTag := rtField.Tag
// for _, tag := range in.Option.Tags {
// if mapKey = fieldTag.Get(tag); mapKey != "" {
// break
// }
// }
// if mapKey == "" {
// mapKey = fieldName
// } else {
// // Support json tag feature: -, omitempty
// mapKey = strings.TrimSpace(mapKey)
// if mapKey == "-" {
// continue
// }
// array := strings.Split(mapKey, ",")
// if len(array) > 1 {
// switch strings.TrimSpace(array[1]) {
// case "omitempty":
// if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) {
// continue
// } else {
// mapKey = strings.TrimSpace(array[0])
// }
// default:
// mapKey = strings.TrimSpace(array[0])
// }
// }
// if mapKey == "" {
// mapKey = fieldName
// }
// }
// if in.Recursive || rtField.Anonymous {
// // Do map converting recursively.
// var (
// rvAttrField = rvField
// rvAttrKind = rvField.Kind()
// )
// if rvAttrKind == reflect.Ptr {
// rvAttrField = rvField.Elem()
// rvAttrKind = rvAttrField.Kind()
// }
// switch rvAttrKind {
// case reflect.Struct:
// // Embedded struct and has no fields, just ignores it.
// // Eg: gmeta.Meta
// if rvAttrField.Type().NumField() == 0 {
// continue
// }
// var (
// hasNoTag = mapKey == fieldName
// // DO NOT use rvAttrField.Interface() here,
// // as it might be changed from pointer to struct.
// rvInterface = rvField.Interface()
// )
// switch {
// case hasNoTag && rtField.Anonymous:
// // It means this attribute field has no tag.
// // Overwrite the attribute with sub-struct attribute fields.
// anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: rvInterface,
// Recursive: true,
// Option: in.Option,
// })
// if m, ok := anonymousValue.(map[string]any); ok {
// for k, v := range m {
// dataMap[k] = v
// }
// } else {
// dataMap[mapKey] = rvInterface
// }
//
// // It means this attribute field has desired tag.
// case !hasNoTag && rtField.Anonymous:
// dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: rvInterface,
// Recursive: true,
// Option: in.Option,
// })
//
// default:
// dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: rvInterface,
// Recursive: in.Recursive,
// Option: in.Option,
// })
// }
//
// // The struct attribute is type of slice.
// case reflect.Array, reflect.Slice:
// length := rvAttrField.Len()
// if length == 0 {
// dataMap[mapKey] = rvAttrField.Interface()
// break
// }
// array := make([]any, length)
// for arrayIndex := 0; arrayIndex < length; arrayIndex++ {
// array[arrayIndex] = c.doMapConvertForMapOrStructValue(
// doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: rvAttrField.Index(arrayIndex).Interface(),
// Recursive: in.Recursive,
// Option: in.Option,
// },
// )
// }
// dataMap[mapKey] = array
// case reflect.Map:
// var (
// mapIter = rvAttrField.MapRange()
// nestedMap = make(map[string]any)
// )
// for mapIter.Next() {
// nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue(
// doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: mapIter.Value().Interface(),
// Recursive: in.Recursive,
// Option: in.Option,
// },
// )
// }
// dataMap[mapKey] = nestedMap
// default:
// if rvField.IsValid() {
// dataMap[mapKey] = reflectValue.Field(i).Interface()
// } else {
// dataMap[mapKey] = nil
// }
// }
// } else {
// // No recursive map value converting
// if rvField.IsValid() {
// dataMap[mapKey] = reflectValue.Field(i).Interface()
// } else {
// dataMap[mapKey] = nil
// }
// }
// }
// if !in.MustMapReturn && len(dataMap) == 0 {
// return in.Value
// }
// return dataMap
//
// // The given value is type of slice.
// case reflect.Array, reflect.Slice:
// length := reflectValue.Len()
// if length == 0 {
// break
// }
// array := make([]any, reflectValue.Len())
// for i := 0; i < length; i++ {
// array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
// IsRoot: false,
// Value: reflectValue.Index(i).Interface(),
// Recursive: in.Recursive,
// Option: in.Option,
// })
// }
// return array
//
// default:
// }
// return in.Value
//}

View File

@ -1,7 +0,0 @@
// 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

View File

@ -23,7 +23,7 @@ import (
//
// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
// sense only if the items of original map `params` is type struct.
func (c *Converter) MapToMap(params any, pointer any, mapping ...map[string]string) (err error) {
func (c *impConverter) MapToMap(params any, pointer any, mapping ...map[string]string) (err error) {
var (
paramsRv reflect.Value
paramsKind reflect.Kind
@ -98,27 +98,27 @@ func (c *Converter) MapToMap(params any, pointer any, mapping ...map[string]stri
return err
}
default:
mapValue.Set(
reflect.ValueOf(
c.doConvert(doConvertInput{
FromValue: paramsRv.MapIndex(key).Interface(),
ToTypeName: pointerValueType.String(),
ReferValue: mapValue,
Extra: nil,
}),
),
)
convertResult, err := c.doConvert(doConvertInput{
FromValue: paramsRv.MapIndex(key).Interface(),
ToTypeName: pointerValueType.String(),
ReferValue: mapValue,
Extra: nil,
})
if err != nil {
return err
}
mapValue.Set(reflect.ValueOf(convertResult))
}
var mapKey = reflect.ValueOf(
c.doConvert(
doConvertInput{
FromValue: key.Interface(),
ToTypeName: pointerKeyType.Name(),
ReferValue: reflect.New(pointerKeyType).Elem().Interface(),
Extra: nil,
},
),
)
convertResult, err := c.doConvert(doConvertInput{
FromValue: key.Interface(),
ToTypeName: pointerKeyType.Name(),
ReferValue: reflect.New(pointerKeyType).Elem().Interface(),
Extra: nil,
})
if err != nil {
return err
}
var mapKey = reflect.ValueOf(convertResult)
dataMap.SetMapIndex(mapKey, mapValue)
}
pointerRv.Set(dataMap)

View File

@ -21,7 +21,7 @@ import (
//
// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
// sense only if the item of `params` is type struct.
func (c *Converter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) {
func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) {
// Params and its element type check.
var (
paramsRv reflect.Value

View File

@ -6,7 +6,7 @@
package gconv
func (c *Converter) Rune(any any) (rune, error) {
func (c *impConverter) Rune(any any) (rune, error) {
if v, ok := any.(rune); ok {
return v, nil
}
@ -17,7 +17,7 @@ func (c *Converter) Rune(any any) (rune, error) {
return v, nil
}
func (c *Converter) Runes(any any) ([]rune, error) {
func (c *impConverter) Runes(any any) ([]rune, error) {
if v, ok := any.([]rune); ok {
return v, nil
}

View File

@ -15,7 +15,7 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *Converter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) {
func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) {
// Check if srcValue is nil, in which case no conversion is needed
if srcValue == nil {
return nil
@ -182,7 +182,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[
// - dstPointer: The destination pointer to convert to
// - dstPointerReflectType: The reflection type of the destination pointer
// - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names
func (c *Converter) doScanForComplicatedTypes(
func (c *impConverter) doScanForComplicatedTypes(
srcValue, dstPointer any,
dstPointerReflectType reflect.Type,
paramKeyToAttrMap ...map[string]string,

View File

@ -0,0 +1,142 @@
// 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"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
type SliceOption struct {
// FailBreak specifies whether to break converting the next element
// if one element conversion fails in slice.
FailBreak bool
}
// SliceAny converts `any` to []any.
func (c *impConverter) SliceAny(any interface{}, option SliceOption) ([]any, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
array []interface{}
)
switch value := any.(type) {
case []interface{}:
array = value
case []string:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int8:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int16:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int32:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
case []uint16:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint32:
for _, v := range value {
array = append(array, v)
}
case []uint64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []bool:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []float32:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []float64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
}
if array != nil {
return array, err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return v.Interfaces(), err
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]interface{}, length)
)
for i := 0; i < length; i++ {
slice[i] = originValueAndKind.OriginValue.Index(i).Interface()
}
return slice, err
default:
return []interface{}{any}, err
}
}

View File

@ -0,0 +1,417 @@
// 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"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceFloat32 converts `any` to []float32.
func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]float32, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
f float32
array []float32 = nil
)
switch value := any.(type) {
case []string:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int8:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int16:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int32:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int64:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []uint:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []float32{}, err
}
if utils.IsNumeric(value) {
f, err = c.Float32(value)
if err != nil && option.FailBreak {
return nil, err
}
return []float32{f}, err
}
case []uint16:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []uint32:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []uint64:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []bool:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []float32:
array = value
case []float64:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []interface{}:
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
}
if array != nil {
return array, err
}
if v, ok := any.(localinterface.IFloats); ok {
return c.SliceFloat32(v.Floats(), option)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceFloat32(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]float32, length)
)
for i := 0; i < length; i++ {
f, err = c.Float32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = f
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []float32{}, err
}
f, err = c.Float32(any)
if err != nil && option.FailBreak {
return nil, err
}
return []float32{f}, err
}
}
// SliceFloat64 converts `any` to []float64.
func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]float64, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
f float64
array []float64 = nil
)
switch value := any.(type) {
case []string:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int8:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int16:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int32:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []int64:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []uint:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []float64{}, err
}
if utils.IsNumeric(value) {
f, err = c.Float64(value)
if err != nil && option.FailBreak {
return nil, err
}
return []float64{f}, err
}
case []uint16:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []uint32:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []uint64:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []bool:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []float32:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
case []float64:
array = value
case []interface{}:
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = f
}
}
if array != nil {
return array, err
}
if v, ok := any.(localinterface.IFloats); ok {
return v.Floats(), err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceFloat64(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]float64, length)
)
for i := 0; i < length; i++ {
f, err = c.Float64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = f
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []float64{}, err
}
f, err = c.Float64(any)
if err != nil && option.FailBreak {
return nil, err
}
return []float64{f}, err
}
}

View File

@ -0,0 +1,536 @@
// 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"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceInt converts `any` to []int.
func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ii int
array []int = nil
)
switch value := any.(type) {
case []string:
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []int:
array = value
case []int8:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int16:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int32:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int64:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []int{}, err
}
if utils.IsNumeric(value) {
ii, err = c.Int(value)
if err != nil && option.FailBreak {
return nil, err
}
return []int{ii}, err
}
case []uint16:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint32:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint64:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []bool:
array = make([]int, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []float64:
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []interface{}:
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case [][]byte:
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
}
if array != nil {
return array, err
}
if v, ok := any.(localinterface.IInts); ok {
return v.Ints(), err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceInt(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]int, length)
)
for i := 0; i < length; i++ {
ii, err = c.Int(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = ii
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []int{}, err
}
ii, err = c.Int(any)
if err != nil && option.FailBreak {
return nil, err
}
return []int{ii}, err
}
}
// SliceInt32 converts `any` to []int32.
func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ii int32
array []int32 = nil
)
switch value := any.(type) {
case []string:
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []int:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int8:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int16:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int32:
array = value
case []int64:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []int32{}, err
}
if utils.IsNumeric(value) {
ii, err = c.Int32(value)
if err != nil && option.FailBreak {
return nil, err
}
return []int32{ii}, err
}
case []uint16:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint32:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint64:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []bool:
array = make([]int32, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []float64:
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []interface{}:
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case [][]byte:
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
}
if array != nil {
return array, err
}
if v, ok := any.(localinterface.IInts); ok {
return c.SliceInt32(v.Ints(), option)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceInt32(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]int32, length)
)
for i := 0; i < length; i++ {
ii, err = c.Int32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = ii
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []int32{}, err
}
ii, err = c.Int32(any)
if err != nil && option.FailBreak {
return nil, err
}
return []int32{ii}, err
}
}
// SliceInt64 converts `any` to []int64.
func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ii int64
array []int64 = nil
)
switch value := any.(type) {
case []string:
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []int:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int8:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int16:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int32:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int64:
array = value
case []uint:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []int64{}, err
}
if utils.IsNumeric(value) {
ii, err = c.Int64(value)
if err != nil && option.FailBreak {
return nil, err
}
return []int64{ii}, err
}
case []uint16:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint32:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint64:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []bool:
array = make([]int64, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []float64:
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case []interface{}:
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
case [][]byte:
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ii
}
}
if array != nil {
return array, err
}
if v, ok := any.(localinterface.IInts); ok {
return c.SliceInt64(v.Ints(), option)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceInt64(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]int64, length)
)
for i := 0; i < length; i++ {
ii, err = c.Int64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = ii
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []int64{}, err
}
ii, err = c.Int64(any)
if err != nil && option.FailBreak {
return nil, err
}
return []int64{ii}, err
}
}

View File

@ -0,0 +1,59 @@
// 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 "github.com/gogf/gf/v2/internal/json"
// SliceMap converts `value` to []map[string]any.
// Note that it automatically checks and converts json string to []map if `value` is string/[]byte.
func (c *impConverter) SliceMap(value any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) {
if value == nil {
return nil, nil
}
switch r := value.(type) {
case string:
list := make([]map[string]any, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil {
return nil, err
}
return list, nil
}
return nil, nil
case []byte:
list := make([]map[string]any, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.UnmarshalUseNumber(r, &list); err != nil {
return nil, err
}
return list, nil
}
return nil, nil
case []map[string]any:
return r, nil
default:
array, err := c.SliceAny(value, sliceOption)
if err != nil {
return nil, err
}
if len(array) == 0 {
return nil, nil
}
list := make([]map[string]any, len(array))
for k, v := range array {
m := Map(v, mapOption)
//if err != nil {
// return nil, err
//}
list[k] = m
}
return list, nil
}
}

View File

@ -0,0 +1,216 @@
// 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"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceStr converts `any` to []string.
func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
s string
array []string = nil
)
switch value := any.(type) {
case []int:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []int8:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int16:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []int32:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []int64:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []uint:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
return array, err
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []string{}, err
}
return []string{value}, err
case []uint16:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []uint32:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []uint64:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []bool:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []float32:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []float64:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []interface{}:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
case []string:
array = value
case [][]byte:
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = s
}
}
if array != nil {
return array, err
}
if v, ok := any.(localinterface.IStrings); ok {
return v.Strings(), err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceStr(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]string, length)
)
for i := 0; i < length; i++ {
s, err = c.String(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = s
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []string{}, err
}
s, err = c.String(any)
if err != nil && option.FailBreak {
return nil, err
}
return []string{s}, err
}
}

View File

@ -0,0 +1,527 @@
// 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"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceUint converts `any` to []uint.
func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ui uint
array []uint = nil
)
switch value := any.(type) {
case []string:
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []int8:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int16:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint:
array = value
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []uint{}, err
}
if utils.IsNumeric(value) {
ui, err = c.Uint(value)
if err != nil && option.FailBreak {
return nil, err
}
return []uint{ui}, err
}
case []uint16:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []bool:
array = make([]uint, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []float64:
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []interface{}:
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case [][]byte:
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
}
if array != nil {
return array, err
}
// Default handler.
if v, ok := any.(localinterface.IUints); ok {
return v.Uints(), err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceUint(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]uint, length)
)
for i := 0; i < length; i++ {
ui, err = c.Uint(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = ui
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []uint{}, err
}
ui, err = c.Uint(any)
if err != nil && option.FailBreak {
return nil, err
}
return []uint{ui}, err
}
}
// SliceUint32 converts `any` to []uint32.
func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint32, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ui uint32
array []uint32 = nil
)
switch value := any.(type) {
case []string:
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []int8:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int16:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int32:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int64:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []uint32{}, err
}
if utils.IsNumeric(value) {
ui, err = c.Uint32(value)
if err != nil && option.FailBreak {
return nil, err
}
return []uint32{ui}, err
}
case []uint16:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint32:
array = value
case []uint64:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []bool:
array = make([]uint32, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []float64:
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []interface{}:
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case [][]byte:
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
}
if array != nil {
return array, err
}
// Default handler.
if v, ok := any.(localinterface.IUints); ok {
return c.SliceUint32(v.Uints(), option)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceUint32(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]uint32, length)
)
for i := 0; i < length; i++ {
ui, err = c.Uint32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = ui
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []uint32{}, err
}
ui, err = c.Uint32(any)
if err != nil && option.FailBreak {
return nil, err
}
return []uint32{ui}, err
}
}
// SliceUint64 converts `any` to []uint64.
func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint64, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ui uint64
array []uint64 = nil
)
switch value := any.(type) {
case []string:
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []int8:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int16:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int32:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int64:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint8:
if json.Valid(value) {
if err = json.UnmarshalUseNumber(value, &array); array != nil {
return array, err
}
}
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if err = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array, err
}
}
if value == "" {
return []uint64{}, err
}
if utils.IsNumeric(value) {
ui, err = c.Uint64(value)
if err != nil && option.FailBreak {
return nil, err
}
return []uint64{ui}, err
}
case []uint16:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint32:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint64:
array = value
case []bool:
array = make([]uint64, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []float64:
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case []interface{}:
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
case [][]byte:
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.FailBreak {
return nil, err
}
array[k] = ui
}
}
if array != nil {
return array, err
}
// Default handler.
if v, ok := any.(localinterface.IUints); ok {
return c.SliceUint64(v.Uints(), option)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceUint64(v.Interfaces(), option)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]uint64, length)
)
for i := 0; i < length; i++ {
ui, err = c.Uint64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.FailBreak {
return nil, err
}
slice[i] = ui
}
return slice, err
default:
if originValueAndKind.OriginValue.IsZero() {
return []uint64{}, err
}
ui, err = c.Uint64(any)
if err != nil && option.FailBreak {
return nil, err
}
return []uint64{ui}, err
}
}

View File

@ -20,7 +20,7 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *Converter) String(any any) (string, error) {
func (c *impConverter) String(any any) (string, error) {
if empty.IsNil(any) {
return "", nil
}

View File

@ -20,7 +20,7 @@ import (
)
// Struct is the core internal converting function for any data to struct.
func (c *Converter) Struct(
func (c *impConverter) Struct(
params any,
pointer any,
paramKeyToAttrMap map[string]string,
@ -147,7 +147,7 @@ func (c *Converter) Struct(
return nil
}
// Get struct info from cache or parse struct and cache the struct info.
cachedStructInfo := c.internalConvertConfig.GetCachedStructInfo(
cachedStructInfo := c.internalConverter.GetCachedStructInfo(
pointerElemReflectValue.Type(), priorityTag,
)
// Nothing to be converted.
@ -204,7 +204,7 @@ func (c *Converter) Struct(
)
}
func (c *Converter) setOtherSameNameField(
func (c *impConverter) setOtherSameNameField(
cachedFieldInfo *structcache.CachedFieldInfo,
srcValue any,
structValue reflect.Value,
@ -220,7 +220,7 @@ func (c *Converter) setOtherSameNameField(
return nil
}
func (c *Converter) bindStructWithLoopFieldInfos(
func (c *impConverter) bindStructWithLoopFieldInfos(
paramsMap map[string]any,
structValue reflect.Value,
paramKeyToAttrMap map[string]string,
@ -316,7 +316,7 @@ func fuzzyMatchingFieldName(
// bindVarToStructField sets value to struct object attribute by name.
// each value to attribute converting comes into in this function.
func (c *Converter) bindVarToStructField(
func (c *impConverter) bindVarToStructField(
cachedFieldInfo *structcache.CachedFieldInfo,
fieldValue reflect.Value,
srcValue any,
@ -439,7 +439,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value a
}
// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.
func (c *Converter) bindVarToReflectValue(
func (c *impConverter) bindVarToReflectValue(
structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string,
) (err error) {
// JSON content converting.

View File

@ -20,7 +20,7 @@ import (
// The parameter `pointer` should be type of pointer to slice of struct.
// Note that if `pointer` is a pointer to another pointer of type of slice of struct,
// it will create the struct/pointer internally.
func (c *Converter) Structs(
func (c *impConverter) Structs(
params any, pointer any, paramKeyToAttrMap map[string]string, priorityTag string,
) (err error) {
defer func() {

View File

@ -16,7 +16,7 @@ import (
)
// Time converts `any` to time.Time.
func (c *Converter) Time(any interface{}, format ...string) (time.Time, error) {
func (c *impConverter) Time(any interface{}, format ...string) (time.Time, error) {
// It's already this type.
if len(format) == 0 {
if v, ok := any.(time.Time); ok {
@ -36,7 +36,7 @@ func (c *Converter) Time(any interface{}, format ...string) (time.Time, error) {
// Duration converts `any` to time.Duration.
// If `any` is string, then it uses time.ParseDuration to convert it.
// If `any` is numeric, then it converts `any` as nanoseconds.
func (c *Converter) Duration(any interface{}) (time.Duration, error) {
func (c *impConverter) Duration(any interface{}) (time.Duration, error) {
// It's already this type.
if v, ok := any.(time.Duration); ok {
return v, nil
@ -60,7 +60,7 @@ func (c *Converter) Duration(any interface{}) (time.Duration, error) {
// It returns the converted value that matched the first format of the formats slice.
// If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric,
// or using gtime.StrToTime if `any` is string.
func (c *Converter) GTime(any interface{}, format ...string) (*gtime.Time, error) {
func (c *impConverter) GTime(any interface{}, format ...string) (*gtime.Time, error) {
if empty.IsNil(any) {
return nil, nil
}

View File

@ -18,7 +18,7 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *Converter) Uint(any any) (uint, error) {
func (c *impConverter) Uint(any any) (uint, error) {
if empty.IsNil(any) {
return 0, nil
}
@ -29,7 +29,7 @@ func (c *Converter) Uint(any any) (uint, error) {
return uint(v), err
}
func (c *Converter) Uint8(any any) (uint8, error) {
func (c *impConverter) Uint8(any any) (uint8, error) {
if empty.IsNil(any) {
return 0, nil
}
@ -40,7 +40,7 @@ func (c *Converter) Uint8(any any) (uint8, error) {
return uint8(v), err
}
func (c *Converter) Uint16(any any) (uint16, error) {
func (c *impConverter) Uint16(any any) (uint16, error) {
if empty.IsNil(any) {
return 0, nil
}
@ -51,7 +51,7 @@ func (c *Converter) Uint16(any any) (uint16, error) {
return uint16(v), err
}
func (c *Converter) Uint32(any any) (uint32, error) {
func (c *impConverter) Uint32(any any) (uint32, error) {
if empty.IsNil(any) {
return 0, nil
}
@ -62,7 +62,7 @@ func (c *Converter) Uint32(any any) (uint32, error) {
return uint32(v), err
}
func (c *Converter) Uint64(any any) (uint64, error) {
func (c *impConverter) Uint64(any any) (uint64, error) {
if empty.IsNil(any) {
return 0, nil
}

View File

@ -6,17 +6,6 @@
package gconv
import (
"bytes"
"reflect"
"strings"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceAny is alias of Interfaces.
func SliceAny(any interface{}) []interface{} {
return Interfaces(any)
@ -24,123 +13,6 @@ func SliceAny(any interface{}) []interface{} {
// Interfaces converts `any` to []interface{}.
func Interfaces(any interface{}) []interface{} {
if empty.IsNil(any) {
return nil
}
var array []interface{}
switch value := any.(type) {
case []interface{}:
array = value
case []string:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int8:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int16:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int32:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []int64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
case []uint16:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []uint32:
for _, v := range value {
array = append(array, v)
}
case []uint64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []bool:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []float32:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
case []float64:
array = make([]interface{}, len(value))
for k, v := range value {
array[k] = v
}
}
if array != nil {
return array
}
if v, ok := any.(localinterface.IInterfaces); ok {
return v.Interfaces()
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]interface{}, length)
)
for i := 0; i < length; i++ {
slice[i] = originValueAndKind.OriginValue.Index(i).Interface()
}
return slice
default:
return []interface{}{any}
}
result, _ := defaultConverter.SliceAny(any, SliceOption{})
return result
}

View File

@ -6,18 +6,6 @@
package gconv
import (
"bytes"
"reflect"
"strings"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceFloat is alias of Floats.
func SliceFloat(any interface{}) []float64 {
return Floats(any)
@ -40,270 +28,12 @@ func Floats(any interface{}) []float64 {
// Float32s converts `any` to []float32.
func Float32s(any interface{}) []float32 {
if empty.IsNil(any) {
return nil
}
var (
array []float32 = nil
)
switch value := any.(type) {
case []string:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int8:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int16:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int32:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []int64:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []uint:
for _, v := range value {
array = append(array, Float32(v))
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []float32{}
}
if utils.IsNumeric(value) {
return []float32{Float32(value)}
}
case []uint16:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []uint32:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []uint64:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []bool:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []float32:
array = value
case []float64:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
case []interface{}:
array = make([]float32, len(value))
for k, v := range value {
array[k] = Float32(v)
}
}
if array != nil {
return array
}
if v, ok := any.(localinterface.IFloats); ok {
return Float32s(v.Floats())
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Float32s(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]float32, length)
)
for i := 0; i < length; i++ {
slice[i] = Float32(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []float32{}
}
return []float32{Float32(any)}
}
result, _ := defaultConverter.SliceFloat32(any, SliceOption{})
return result
}
// Float64s converts `any` to []float64.
func Float64s(any interface{}) []float64 {
if empty.IsNil(any) {
return nil
}
var (
array []float64 = nil
)
switch value := any.(type) {
case []string:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int8:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int16:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []int64:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint:
for _, v := range value {
array = append(array, Float64(v))
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []float64{}
}
if utils.IsNumeric(value) {
return []float64{Float64(value)}
}
case []uint16:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []uint64:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []bool:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []float32:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
case []float64:
array = value
case []interface{}:
array = make([]float64, len(value))
for k, v := range value {
array[k] = Float64(v)
}
}
if array != nil {
return array
}
if v, ok := any.(localinterface.IFloats); ok {
return v.Floats()
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Floats(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]float64, length)
)
for i := 0; i < length; i++ {
slice[i] = Float64(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []float64{}
}
return []float64{Float64(any)}
}
result, _ := defaultConverter.SliceFloat64(any, SliceOption{})
return result
}

View File

@ -6,464 +6,35 @@
package gconv
import (
"bytes"
"reflect"
"strings"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceInt is alias of Ints.
func SliceInt(any interface{}) []int {
func SliceInt(any any) []int {
return Ints(any)
}
// SliceInt32 is alias of Int32s.
func SliceInt32(any interface{}) []int32 {
func SliceInt32(any any) []int32 {
return Int32s(any)
}
// SliceInt64 is alias of Int64s.
func SliceInt64(any interface{}) []int64 {
func SliceInt64(any any) []int64 {
return Int64s(any)
}
// Ints converts `any` to []int.
func Ints(any interface{}) []int {
if empty.IsNil(any) {
return nil
}
var (
array []int = nil
)
switch value := any.(type) {
case []string:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []int:
array = value
case []int8:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int16:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int32:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []int64:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []int{}
}
if utils.IsNumeric(value) {
return []int{Int(value)}
}
case []uint16:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint32:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []uint64:
array = make([]int, len(value))
for k, v := range value {
array[k] = int(v)
}
case []bool:
array = make([]int, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []float64:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case []interface{}:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
case [][]byte:
array = make([]int, len(value))
for k, v := range value {
array[k] = Int(v)
}
}
if array != nil {
return array
}
if v, ok := any.(localinterface.IInts); ok {
return v.Ints()
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Ints(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]int, length)
)
for i := 0; i < length; i++ {
slice[i] = Int(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []int{}
}
return []int{Int(any)}
}
func Ints(any any) []int {
result, _ := defaultConverter.SliceInt(any, SliceOption{})
return result
}
// Int32s converts `any` to []int32.
func Int32s(any interface{}) []int32 {
if empty.IsNil(any) {
return nil
}
var (
array []int32 = nil
)
switch value := any.(type) {
case []string:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
case []int:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int8:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int16:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []int32:
array = value
case []int64:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []int32{}
}
if utils.IsNumeric(value) {
return []int32{Int32(value)}
}
case []uint16:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint32:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []uint64:
array = make([]int32, len(value))
for k, v := range value {
array[k] = int32(v)
}
case []bool:
array = make([]int32, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
case []float64:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
case []interface{}:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
case [][]byte:
array = make([]int32, len(value))
for k, v := range value {
array[k] = Int32(v)
}
}
if array != nil {
return array
}
if v, ok := any.(localinterface.IInts); ok {
return Int32s(v.Ints())
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Int32s(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]int32, length)
)
for i := 0; i < length; i++ {
slice[i] = Int32(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []int32{}
}
return []int32{Int32(any)}
}
func Int32s(any any) []int32 {
result, _ := defaultConverter.SliceInt32(any, SliceOption{})
return result
}
// Int64s converts `any` to []int64.
func Int64s(any interface{}) []int64 {
if empty.IsNil(any) {
return nil
}
var (
array []int64 = nil
)
switch value := any.(type) {
case []string:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
case []int:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int8:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int16:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int32:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []int64:
array = value
case []uint:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []int64{}
}
if utils.IsNumeric(value) {
return []int64{Int64(value)}
}
case []uint16:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint32:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []uint64:
array = make([]int64, len(value))
for k, v := range value {
array[k] = int64(v)
}
case []bool:
array = make([]int64, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
case []float64:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
case []interface{}:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
case [][]byte:
array = make([]int64, len(value))
for k, v := range value {
array[k] = Int64(v)
}
}
if array != nil {
return array
}
if v, ok := any.(localinterface.IInts); ok {
return Int64s(v.Ints())
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Int64s(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]int64, length)
)
for i := 0; i < length; i++ {
slice[i] = Int64(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []int64{}
}
return []int64{Int64(any)}
}
func Int64s(any any) []int64 {
result, _ := defaultConverter.SliceInt64(any, SliceOption{})
return result
}

View File

@ -6,17 +6,6 @@
package gconv
import (
"bytes"
"reflect"
"strings"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceStr is alias of Strings.
func SliceStr(any interface{}) []string {
return Strings(any)
@ -24,140 +13,6 @@ func SliceStr(any interface{}) []string {
// Strings converts `any` to []string.
func Strings(any interface{}) []string {
if empty.IsNil(any) {
return nil
}
var (
array []string = nil
)
switch value := any.(type) {
case []int:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int8:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int16:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []int64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
return array
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []string{}
}
return []string{value}
case []uint16:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []uint64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []bool:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []float32:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []float64:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []interface{}:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
case []string:
array = value
case [][]byte:
array = make([]string, len(value))
for k, v := range value {
array[k] = String(v)
}
}
if array != nil {
return array
}
if v, ok := any.(localinterface.IStrings); ok {
return v.Strings()
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Strings(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]string, length)
)
for i := 0; i < length; i++ {
slice[i] = String(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []string{}
}
return []string{String(any)}
}
result, _ := defaultConverter.SliceStr(any, SliceOption{})
return result
}

View File

@ -6,18 +6,6 @@
package gconv
import (
"bytes"
"reflect"
"strings"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// SliceUint is alias of Uints.
func SliceUint(any interface{}) []uint {
return Uints(any)
@ -35,426 +23,18 @@ func SliceUint64(any interface{}) []uint64 {
// Uints converts `any` to []uint.
func Uints(any interface{}) []uint {
if empty.IsNil(any) {
return nil
}
var (
array []uint = nil
)
switch value := any.(type) {
case []string:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []int8:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int16:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []int64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint:
array = value
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []uint{}
}
if utils.IsNumeric(value) {
return []uint{Uint(value)}
}
case []uint16:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []uint64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = uint(v)
}
case []bool:
array = make([]uint, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []float64:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case []interface{}:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
case [][]byte:
array = make([]uint, len(value))
for k, v := range value {
array[k] = Uint(v)
}
}
if array != nil {
return array
}
// Default handler.
if v, ok := any.(localinterface.IUints); ok {
return v.Uints()
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Uints(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]uint, length)
)
for i := 0; i < length; i++ {
slice[i] = Uint(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []uint{}
}
return []uint{Uint(any)}
}
result, _ := defaultConverter.SliceUint(any, SliceOption{})
return result
}
// Uint32s converts `any` to []uint32.
func Uint32s(any interface{}) []uint32 {
if empty.IsNil(any) {
return nil
}
var (
array []uint32 = nil
)
switch value := any.(type) {
case []string:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
case []int8:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int16:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int32:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []int64:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []uint32{}
}
if utils.IsNumeric(value) {
return []uint32{Uint32(value)}
}
case []uint16:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []uint32:
array = value
case []uint64:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = uint32(v)
}
case []bool:
array = make([]uint32, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
case []float64:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
case []interface{}:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
case [][]byte:
array = make([]uint32, len(value))
for k, v := range value {
array[k] = Uint32(v)
}
}
if array != nil {
return array
}
// Default handler.
if v, ok := any.(localinterface.IUints); ok {
return Uint32s(v.Uints())
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Uint32s(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]uint32, length)
)
for i := 0; i < length; i++ {
slice[i] = Uint32(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []uint32{}
}
return []uint32{Uint32(any)}
}
result, _ := defaultConverter.SliceUint32(any, SliceOption{})
return result
}
// Uint64s converts `any` to []uint64.
func Uint64s(any interface{}) []uint64 {
if empty.IsNil(any) {
return nil
}
var (
array []uint64 = nil
)
switch value := any.(type) {
case []string:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
case []int8:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int16:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int32:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []int64:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint8:
if json.Valid(value) {
if _ = json.UnmarshalUseNumber(value, &array); array != nil {
return array
}
if bytes.EqualFold([]byte("null"), value) {
return nil
}
}
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case string:
byteValue := []byte(value)
if json.Valid(byteValue) {
if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil {
return array
}
if strings.EqualFold(value, "null") {
return nil
}
}
if value == "" {
return []uint64{}
}
if utils.IsNumeric(value) {
return []uint64{Uint64(value)}
}
case []uint16:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint32:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = uint64(v)
}
case []uint64:
array = value
case []bool:
array = make([]uint64, len(value))
for k, v := range value {
if v {
array[k] = 1
} else {
array[k] = 0
}
}
case []float32:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
case []float64:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
case []interface{}:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
case [][]byte:
array = make([]uint64, len(value))
for k, v := range value {
array[k] = Uint64(v)
}
}
if array != nil {
return array
}
// Default handler.
if v, ok := any.(localinterface.IUints); ok {
return Uint64s(v.Uints())
}
if v, ok := any.(localinterface.IInterfaces); ok {
return Uint64s(v.Interfaces())
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Slice, reflect.Array:
var (
length = originValueAndKind.OriginValue.Len()
slice = make([]uint64, length)
)
for i := 0; i < length; i++ {
slice[i] = Uint64(originValueAndKind.OriginValue.Index(i).Interface())
}
return slice
default:
if originValueAndKind.OriginValue.IsZero() {
return []uint64{}
}
return []uint64{Uint64(any)}
}
result, _ := defaultConverter.SliceUint64(any, SliceOption{})
return result
}

View File

@ -14,10 +14,8 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
type AnyConvertFunc func(from any, to reflect.Value) error
// ConvertConfig is the configuration for type converting.
type ConvertConfig struct {
// Converter is the configuration for type converting.
type Converter struct {
// map[reflect.Type]*CachedStructInfo
cachedStructsInfoMap sync.Map
@ -28,9 +26,12 @@ type ConvertConfig struct {
anyToTypeConvertMap map[reflect.Type]AnyConvertFunc
}
// NewConvertConfig creates and returns a new ConvertConfig object.
func NewConvertConfig() *ConvertConfig {
return &ConvertConfig{
// AnyConvertFunc is the function type for converting any to specified type.
type AnyConvertFunc func(from any, to reflect.Value) error
// NewConverter creates and returns a new Converter object.
func NewConverter() *Converter {
return &Converter{
cachedStructsInfoMap: sync.Map{},
typeConverterFuncMap: make(map[reflect.Type]struct{}),
anyToTypeConvertMap: make(map[reflect.Type]AnyConvertFunc),
@ -38,7 +39,7 @@ func NewConvertConfig() *ConvertConfig {
}
// RegisterTypeConvertFunc registers converting function for custom type.
func (cf *ConvertConfig) RegisterTypeConvertFunc(fieldType reflect.Type) {
func (cf *Converter) RegisterTypeConvertFunc(fieldType reflect.Type) {
if fieldType.Kind() == reflect.Ptr {
fieldType = fieldType.Elem()
}
@ -46,7 +47,7 @@ func (cf *ConvertConfig) RegisterTypeConvertFunc(fieldType reflect.Type) {
}
// RegisterAnyConvertFunc registers custom type converting function for specified type.
func (cf *ConvertConfig) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) {
func (cf *Converter) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) {
cf.anyToTypeConvertMap[t] = convertFunc
}

View File

@ -15,7 +15,7 @@ import (
// GetCachedStructInfo retrieves or parses and returns a cached info for certain struct type.
// The given `structType` should be type of struct.
func (cf *ConvertConfig) GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo {
func (cf *Converter) GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo {
if structType.Kind() != reflect.Struct {
return nil
}
@ -44,12 +44,12 @@ func (cf *ConvertConfig) GetCachedStructInfo(structType reflect.Type, priorityTa
return cachedStructInfo
}
func (cf *ConvertConfig) storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) {
func (cf *Converter) storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) {
// Temporarily enabled as an experimental feature
cf.cachedStructsInfoMap.Store(structType, cachedStructInfo)
}
func (cf *ConvertConfig) getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) {
func (cf *Converter) getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) {
// Temporarily enabled as an experimental feature
v, ok := cf.cachedStructsInfoMap.Load(structType)
if ok {
@ -60,7 +60,7 @@ func (cf *ConvertConfig) getCachedConvertStructInfo(structType reflect.Type) (*C
// parseStructToCachedStructInfo parses given struct reflection type and stores its fields info into given CachedStructInfo.
// It stores nothing into CachedStructInfo if given struct reflection type has no fields.
func (cf *ConvertConfig) parseStructToCachedStructInfo(
func (cf *Converter) parseStructToCachedStructInfo(
structType reflect.Type,
fieldIndexes []int,
cachedStructInfo *CachedStructInfo,