1
0
mirror of https://github.com/gogf/gf.git synced 2025-04-05 03:05:05 +08:00

refract(util/gconv): change Converter interface definition for more convenient usage (#4202)

This commit is contained in:
John Guo 2025-03-14 18:23:07 +08:00 committed by GitHub
parent bb696bb281
commit bc1e1019c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 529 additions and 278 deletions

View File

@ -23,6 +23,6 @@ jobs:
with:
actions: 'check-inactive'
inactive-label: 'inactive'
inactive-day: 7
inactive-day: 30
issue-state: open
exclude-labels: 'bug,planned,$exclude-empty'

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ go.work.sum
node_modules
.docusaurus
output
.example/

View File

@ -201,11 +201,14 @@ func (r Result) Structs(pointer interface{}) (err error) {
return nil
}
var (
sliceOption = gconv.SliceOption{ContinueOnError: true}
mapOption = gconv.StructOption{
sliceOption = gconv.SliceOption{ContinueOnError: true}
structOption = gconv.StructOption{
PriorityTag: OrmTagForStruct,
ContinueOnError: true,
}
)
return converter.Structs(r, pointer, sliceOption, mapOption)
return converter.Structs(r, pointer, gconv.StructsOption{
SliceOption: sliceOption,
StructOption: structOption,
})
}

@ -1 +1 @@
Subproject commit bf0ab5ac16fbf654fc424baf45e96e541a037cb3
Subproject commit b57e4575ce971e6a6e581b1de0e77eccf61705c4

View File

@ -1,3 +1,9 @@
// 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 ghttp_test
import (

View File

@ -35,7 +35,7 @@ type Converter interface {
// ConverterForBasic is the basic converting interface.
type ConverterForBasic interface {
Scan(srcValue, dstPointer any, option ScanOption) (err error)
Scan(srcValue, dstPointer any, option ...ScanOption) (err error)
String(any any) (string, error)
Bool(any any) (bool, error)
Rune(any any) (rune, error)
@ -74,37 +74,37 @@ type ConverterForFloat interface {
// ConverterForMap is the converting interface for map.
type ConverterForMap interface {
Map(v any, option MapOption) (map[string]any, error)
MapStrStr(v any, option MapOption) (map[string]string, error)
Map(v any, option ...MapOption) (map[string]any, error)
MapStrStr(v any, option ...MapOption) (map[string]string, error)
}
// ConverterForSlice is the converting interface for slice.
type ConverterForSlice interface {
Bytes(v any) ([]byte, error)
Runes(v any) ([]rune, error)
SliceAny(v any, option SliceOption) ([]any, error)
SliceFloat32(v any, option SliceOption) ([]float32, error)
SliceFloat64(v any, option SliceOption) ([]float64, error)
SliceInt(v any, option SliceOption) ([]int, error)
SliceInt32(v any, option SliceOption) ([]int32, error)
SliceInt64(v any, option SliceOption) ([]int64, error)
SliceUint(v any, option SliceOption) ([]uint, error)
SliceUint32(v any, option SliceOption) ([]uint32, error)
SliceUint64(v any, option SliceOption) ([]uint64, error)
SliceStr(v any, option SliceOption) ([]string, error)
SliceMap(v any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error)
SliceAny(v any, option ...SliceOption) ([]any, error)
SliceFloat32(v any, option ...SliceOption) ([]float32, error)
SliceFloat64(v any, option ...SliceOption) ([]float64, error)
SliceInt(v any, option ...SliceOption) ([]int, error)
SliceInt32(v any, option ...SliceOption) ([]int32, error)
SliceInt64(v any, option ...SliceOption) ([]int64, error)
SliceUint(v any, option ...SliceOption) ([]uint, error)
SliceUint32(v any, option ...SliceOption) ([]uint32, error)
SliceUint64(v any, option ...SliceOption) ([]uint64, error)
SliceStr(v any, option ...SliceOption) ([]string, error)
SliceMap(v any, option ...SliceMapOption) ([]map[string]any, error)
}
// ConverterForStruct is the converting interface for struct.
type ConverterForStruct interface {
Struct(params, pointer any, option StructOption) (err error)
Structs(params, pointer any, sliceOption SliceOption, structOption StructOption) (err error)
Struct(params, pointer any, option ...StructOption) (err error)
Structs(params, pointer any, option ...StructsOption) (err error)
}
// ConverterForConvert is the converting interface for custom converting.
type ConverterForConvert interface {
ConvertWithRefer(fromValue, referValue any, option ConvertOption) (any, error)
ConvertWithTypeName(fromValue any, toTypeName string, option ConvertOption) (any, error)
ConvertWithRefer(fromValue, referValue any, option ...ConvertOption) (any, error)
ConvertWithTypeName(fromValue any, toTypeName string, option ...ConvertOption) (any, error)
}
// ConverterForRegister is the converting interface for custom converter registration.
@ -123,12 +123,18 @@ type (
// SliceOption is the option for Slice type converting.
SliceOption = converter.SliceOption
// SliceMapOption is the option for SliceMap function.
SliceMapOption = converter.SliceMapOption
// ScanOption is the option for the Scan function.
ScanOption = converter.ScanOption
// StructOption is the option for Struct converting.
StructOption = converter.StructOption
// StructsOption is the option for Structs function.
StructsOption = converter.StructsOption
// ConvertOption is the option for converting.
ConvertOption = converter.ConvertOption
)
@ -142,11 +148,6 @@ var (
defaultConverter = converter.NewConverter()
)
// RegisterAnyConverterFunc registers custom type converting function for specified type.
func RegisterAnyConverterFunc(f AnyConvertFunc, types ...reflect.Type) {
defaultConverter.RegisterAnyConverterFunc(f, types...)
}
// NewConverter creates and returns management object for type converting.
func NewConverter() Converter {
return converter.NewConverter()
@ -162,3 +163,8 @@ func RegisterConverter(fn any) (err error) {
func RegisterTypeConverterFunc(fn any) (err error) {
return defaultConverter.RegisterTypeConverterFunc(fn)
}
// RegisterAnyConverterFunc registers custom type converting function for specified type.
func RegisterAnyConverterFunc(f AnyConvertFunc, types ...reflect.Type) {
defaultConverter.RegisterAnyConverterFunc(f, types...)
}

View File

@ -6,7 +6,10 @@
package gconv
import "github.com/gogf/gf/v2/internal/json"
import (
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv/internal/converter"
)
// SliceMap is alias of Maps.
func SliceMap(any any, option ...MapOption) []map[string]any {
@ -28,9 +31,12 @@ func Maps(value any, option ...MapOption) []map[string]any {
if len(option) > 0 {
mapOption = option[0]
}
result, _ := defaultConverter.SliceMap(value, SliceOption{
ContinueOnError: true,
}, mapOption)
result, _ := defaultConverter.SliceMap(value, SliceMapOption{
MapOption: mapOption,
SliceOption: converter.SliceOption{
ContinueOnError: true,
},
})
return result
}

View File

@ -6,6 +6,8 @@
package gconv
import "github.com/gogf/gf/v2/util/gconv/internal/converter"
// Structs converts any slice to given struct slice.
// Also see Scan, Struct.
func Structs(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) {
@ -21,10 +23,13 @@ func SliceStruct(params any, pointer any, mapping ...map[string]string) (err err
// specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping.
// The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','.
func StructsTag(params any, pointer any, priorityTag string) (err error) {
return defaultConverter.Structs(params, pointer, SliceOption{
ContinueOnError: true,
}, StructOption{
PriorityTag: priorityTag,
ContinueOnError: true,
return defaultConverter.Structs(params, pointer, StructsOption{
SliceOption: converter.SliceOption{
ContinueOnError: true,
},
StructOption: converter.StructOption{
PriorityTag: priorityTag,
ContinueOnError: true,
},
})
}

View File

@ -171,3 +171,72 @@ func TestNewConverter(t *testing.T) {
})
})
}
type UserInput struct {
Name string
Age int
IsActive bool
}
type UserModel struct {
ID int
FullName string
Age int
Status int
}
func userInput2Model(in any, out reflect.Value) error {
if out.Type() == reflect.TypeOf(&UserModel{}) {
if input, ok := in.(UserInput); ok {
model := UserModel{
ID: 1,
FullName: input.Name,
Age: input.Age,
Status: 0,
}
if input.IsActive {
model.Status = 1
}
out.Elem().Set(reflect.ValueOf(model))
return nil
}
return fmt.Errorf("unsupported type %T to UserModel", in)
}
return fmt.Errorf("unsupported type %s", out.Type())
}
func TestConverter_RegisterAnyConverterFunc(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
converter := gconv.NewConverter()
converter.RegisterAnyConverterFunc(userInput2Model, reflect.TypeOf(UserModel{}))
var (
model UserModel
input = UserInput{Name: "sam", Age: 30, IsActive: true}
)
err := converter.Scan(input, &model)
t.AssertNil(err)
t.Assert(model, UserModel{
ID: 1,
FullName: "sam",
Age: 30,
Status: 1,
})
})
gtest.C(t, func(t *gtest.T) {
converter := gconv.NewConverter()
converter.RegisterAnyConverterFunc(userInput2Model, reflect.TypeOf(&UserModel{}))
var (
model UserModel
input = UserInput{Name: "sam", Age: 30, IsActive: true}
)
err := converter.Scan(input, &model)
t.AssertNil(err)
t.Assert(model, UserModel{
ID: 1,
FullName: "sam",
Age: 30,
Status: 1,
})
})
}

View File

@ -345,7 +345,7 @@ func TestMapToMapExtra(t *testing.T) {
expect = make(map[string]interface{})
)
err = gconv.MapToMap(value, &expect)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(value["k1"], expect["k1"])
})

View File

@ -23,20 +23,27 @@ type ConvertOption struct {
StructOption StructOption
}
func (c *Converter) getConvertOption(option ...ConvertOption) ConvertOption {
if len(option) > 0 {
return option[0]
}
return ConvertOption{}
}
// ConvertWithTypeName converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.
func (c *Converter) ConvertWithTypeName(fromValue any, toTypeName string, option ConvertOption) (any, error) {
func (c *Converter) ConvertWithTypeName(fromValue any, toTypeName string, option ...ConvertOption) (any, error) {
return c.doConvert(
doConvertInput{
FromValue: fromValue,
ToTypeName: toTypeName,
ReferValue: nil,
},
option,
c.getConvertOption(option...),
)
}
// ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`.
func (c *Converter) ConvertWithRefer(fromValue, referValue any, option ConvertOption) (any, error) {
func (c *Converter) ConvertWithRefer(fromValue, referValue any, option ...ConvertOption) (any, error) {
var referValueRf reflect.Value
if v, ok := referValue.(reflect.Value); ok {
referValueRf = v
@ -49,7 +56,7 @@ func (c *Converter) ConvertWithRefer(fromValue, referValue any, option ConvertOp
ToTypeName: referValueRf.Type().String(),
ReferValue: referValue,
},
option,
c.getConvertOption(option...),
)
}
@ -354,7 +361,10 @@ func (c *Converter) doConvert(in doConvertInput, option ConvertOption) (converte
return c.Map(in.FromValue, option.MapOption)
case "[]map[string]interface {}":
return c.SliceMap(in.FromValue, option.SliceOption, option.MapOption)
return c.SliceMap(in.FromValue, SliceMapOption{
SliceOption: option.SliceOption,
MapOption: option.MapOption,
})
case "RawMessage", "json.RawMessage":
// issue 3449
@ -463,7 +473,53 @@ func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in
return err
}
func (c *Converter) getRegisteredConverterFuncAndSrcType(
// callCustomConverter call the custom converter. It will try some possible type.
func (c *Converter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) {
// search type converter function.
registeredConverterFunc, srcType, ok := c.getRegisteredTypeConverterFuncAndSrcType(srcReflectValue, dstReflectValue)
if ok {
return c.doCallCustomTypeConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)
}
// search any converter function.
anyConverterFunc := c.getRegisteredAnyConverterFunc(dstReflectValue)
if anyConverterFunc == nil {
return false, nil
}
err = anyConverterFunc(srcReflectValue.Interface(), dstReflectValue)
if err != nil {
return false, err
}
return true, nil
}
func (c *Converter) callCustomConverterWithRefer(
srcReflectValue, referReflectValue reflect.Value,
) (dstReflectValue reflect.Value, converted bool, err error) {
// search type converter function.
registeredConverterFunc, srcType, ok := c.getRegisteredTypeConverterFuncAndSrcType(
srcReflectValue, referReflectValue,
)
if ok {
dstReflectValue = reflect.New(referReflectValue.Type()).Elem()
converted, err = c.doCallCustomTypeConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)
return
}
// search any converter function.
anyConverterFunc := c.getRegisteredAnyConverterFunc(referReflectValue)
if anyConverterFunc == nil {
return reflect.Value{}, false, nil
}
dstReflectValue = reflect.New(referReflectValue.Type()).Elem()
err = anyConverterFunc(srcReflectValue.Interface(), dstReflectValue)
if err != nil {
return reflect.Value{}, false, err
}
return dstReflectValue, true, nil
}
func (c *Converter) getRegisteredTypeConverterFuncAndSrcType(
srcReflectValue, dstReflectValueForRefer reflect.Value,
) (f converterFunc, srcType reflect.Type, ok bool) {
if len(c.typeConverterFuncMap) == 0 {
@ -499,28 +555,28 @@ func (c *Converter) getRegisteredConverterFuncAndSrcType(
return
}
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
func (c *Converter) getRegisteredAnyConverterFunc(dstReflectValueForRefer reflect.Value) (f AnyConvertFunc) {
if c.internalConverter.IsAnyConvertFuncEmpty() {
return nil
}
dstReflectValue = reflect.New(referReflectValue.Type()).Elem()
converted, err = c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)
return
if !dstReflectValueForRefer.IsValid() {
return nil
}
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)
}
return c.internalConverter.GetAnyConvertFuncByType(dstType)
}
// 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(
func (c *Converter) doCallCustomTypeConverter(
srcReflectValue reflect.Value,
dstReflectValue reflect.Value,
registeredConverterFunc converterFunc,

View File

@ -35,34 +35,42 @@ type MapOption struct {
ContinueOnError bool
}
func (c *Converter) getMapOption(option ...MapOption) MapOption {
if len(option) > 0 {
return option[0]
}
return MapOption{}
}
// Map converts any variable `value` to map[string]any. If the parameter `value` is not a
// map/struct/*struct type, then the conversion will fail and returns nil.
//
// If `value` is a struct/*struct object, the second parameter `priorityTagAndFieldName` specifies the most priority
// priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of:
// gconv, json, field name.
func (c *Converter) Map(value any, option MapOption) (map[string]any, error) {
return c.doMapConvert(value, RecursiveTypeAuto, false, option)
func (c *Converter) Map(value any, option ...MapOption) (map[string]any, error) {
return c.doMapConvert(value, RecursiveTypeAuto, false, c.getMapOption(option...))
}
// MapStrStr converts `value` to map[string]string.
// Note that there might be data copy for this map type converting.
func (c *Converter) MapStrStr(value any, option MapOption) (map[string]string, error) {
func (c *Converter) MapStrStr(value any, option ...MapOption) (map[string]string, error) {
if r, ok := value.(map[string]string); ok {
return r, nil
}
m, err := c.Map(value, option)
if err != nil && !option.ContinueOnError {
m, err := c.Map(value, option...)
if err != nil {
return nil, err
}
if len(m) > 0 {
var (
s string
vMap = make(map[string]string, len(m))
s string
vMap = make(map[string]string, len(m))
mapOption = c.getMapOption(option...)
)
for k, v := range m {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !mapOption.ContinueOnError {
return nil, err
}
vMap[k] = s

View File

@ -24,7 +24,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, pointer any, mapping map[string]string, option MapOption,
params, pointer any, mapping map[string]string, option ...MapOption,
) (err error) {
var (
paramsRv reflect.Value
@ -41,11 +41,11 @@ func (c *Converter) MapToMap(
paramsKind = paramsRv.Kind()
}
if paramsKind != reflect.Map {
m, err := c.Map(params, option)
m, err := c.Map(params, option...)
if err != nil {
return err
}
return c.MapToMap(m, pointer, mapping, option)
return c.MapToMap(m, pointer, mapping, option...)
}
// Empty params map, no need continue.
if paramsRv.Len() == 0 {
@ -85,10 +85,11 @@ func (c *Converter) MapToMap(
pointerValueType = pointerRv.Type().Elem()
pointerValueKind = pointerValueType.Kind()
dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))
mapOption = c.getMapOption(option...)
convertOption = ConvertOption{
StructOption: StructOption{ContinueOnError: option.ContinueOnError},
SliceOption: SliceOption{ContinueOnError: option.ContinueOnError},
MapOption: option,
StructOption: StructOption{ContinueOnError: mapOption.ContinueOnError},
SliceOption: SliceOption{ContinueOnError: mapOption.ContinueOnError},
MapOption: mapOption,
}
)
// Retrieve the true element type of target map.
@ -102,7 +103,7 @@ func (c *Converter) MapToMap(
structOption := StructOption{
ParamKeyToAttrMap: mapping,
PriorityTag: "",
ContinueOnError: option.ContinueOnError,
ContinueOnError: mapOption.ContinueOnError,
}
if err = c.Struct(paramsRv.MapIndex(key).Interface(), mapValue, structOption); err != nil {
return err

View File

@ -22,7 +22,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, option MapOption,
params any, pointer any, paramKeyToAttrMap map[string]string, option ...MapOption,
) (err error) {
// Params and its element type check.
var (
@ -105,13 +105,13 @@ func (c *Converter) MapToMaps(
var item reflect.Value
if pointerElemType.Kind() == reflect.Ptr {
item = reflect.New(pointerElemType.Elem())
if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option); err != nil {
if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option...); err != nil {
return err
}
pointerSlice.Index(i).Set(item)
} else {
item = reflect.New(pointerElemType)
if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option); err != nil {
if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option...); err != nil {
return err
}
pointerSlice.Index(i).Set(item.Elem())

View File

@ -25,8 +25,15 @@ type ScanOption struct {
ContinueOnError bool
}
func (c *Converter) getScanOption(option ...ScanOption) ScanOption {
if len(option) > 0 {
return option[0]
}
return ScanOption{}
}
// Scan automatically checks the type of `pointer` and converts `params` to `pointer`.
func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err error) {
func (c *Converter) Scan(srcValue any, dstPointer any, option ...ScanOption) (err error) {
// Check if srcValue is nil, in which case no conversion is needed
if srcValue == nil {
return nil
@ -90,12 +97,12 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e
// Create a new value for the pointer dereference
nextLevelPtr := reflect.New(dstPointerReflectValueElem.Type().Elem())
// Recursively scan into the dereferenced pointer
if err = c.Scan(srcValueReflectValue, nextLevelPtr, option); err == nil {
if err = c.Scan(srcValueReflectValue, nextLevelPtr, option...); err == nil {
dstPointerReflectValueElem.Set(nextLevelPtr)
}
return
}
return c.Scan(srcValueReflectValue, dstPointerReflectValueElem, option)
return c.Scan(srcValueReflectValue, dstPointerReflectValueElem, option...)
}
// Check if srcValue and dstPointer are the same type, in which case direct assignment can be performed
@ -103,11 +110,12 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e
return nil
}
scanOption := c.getScanOption(option...)
// Handle different destination types
switch dstPointerReflectValueElemKind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v, err := c.Int64(srcValue)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetInt(v)
@ -115,7 +123,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v, err := c.Uint64(srcValue)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetUint(v)
@ -123,7 +131,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e
case reflect.Float32, reflect.Float64:
v, err := c.Float64(srcValue)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetFloat(v)
@ -131,7 +139,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e
case reflect.String:
v, err := c.String(srcValue)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetString(v)
@ -139,7 +147,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e
case reflect.Bool:
v, err := c.Bool(srcValue)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetBool(v)
@ -158,7 +166,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e
}
// Special handling for struct or map slice elements
if dstElemKind == reflect.Struct || dstElemKind == reflect.Map {
return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, option)
return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, scanOption)
}
// Handle basic type slice conversions
var srcValueReflectValueKind = srcValueReflectValue.Kind()
@ -172,48 +180,48 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e
switch dstElemType.Kind() {
case reflect.String:
v, err := c.String(srcElem)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
newSlice.Index(i).SetString(v)
case reflect.Int:
v, err := c.Int64(srcElem)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
newSlice.Index(i).SetInt(v)
case reflect.Int64:
v, err := c.Int64(srcElem)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
newSlice.Index(i).SetInt(v)
case reflect.Float64:
v, err := c.Float64(srcElem)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
newSlice.Index(i).SetFloat(v)
case reflect.Bool:
v, err := c.Bool(srcElem)
if err != nil && !option.ContinueOnError {
if err != nil && !scanOption.ContinueOnError {
return err
}
newSlice.Index(i).SetBool(v)
default:
return c.Scan(
srcElem, newSlice.Index(i).Addr().Interface(), option,
srcElem, newSlice.Index(i).Addr().Interface(), option...,
)
}
}
dstPointerReflectValueElem.Set(newSlice)
return nil
}
return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, option)
return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, scanOption)
default:
// Handle complex types (structs, maps, etc.)
return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, option)
return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, scanOption)
}
}
@ -282,7 +290,10 @@ func (c *Converter) doScanForComplicatedTypes(
ContinueOnError: option.ContinueOnError,
}
)
return c.Structs(srcValue, dstPointer, sliceOption, mapOption)
return c.Structs(srcValue, dstPointer, StructsOption{
SliceOption: sliceOption,
StructOption: mapOption,
})
default:
structOption := StructOption{

View File

@ -22,8 +22,15 @@ type SliceOption struct {
ContinueOnError bool
}
func (c *Converter) getSliceOption(option ...SliceOption) SliceOption {
if len(option) > 0 {
return option[0]
}
return SliceOption{}
}
// SliceAny converts `any` to []any.
func (c *Converter) SliceAny(any interface{}, option SliceOption) ([]any, error) {
func (c *Converter) SliceAny(any interface{}, _ ...SliceOption) ([]any, error) {
if empty.IsNil(any) {
return nil, nil
}

View File

@ -17,21 +17,22 @@ import (
)
// SliceFloat32 converts `any` to []float32.
func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32, error) {
func (c *Converter) SliceFloat32(any interface{}, option ...SliceOption) ([]float32, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
f float32
array []float32 = nil
err error
f float32
array []float32 = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -40,7 +41,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -49,7 +50,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -58,7 +59,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -67,7 +68,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -76,7 +77,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -85,7 +86,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -99,7 +100,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -116,7 +117,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
}
if utils.IsNumeric(value) {
f, err = c.Float32(value)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []float32{f}, err
@ -125,7 +126,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -134,7 +135,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -143,7 +144,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -152,7 +153,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -163,7 +164,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -172,7 +173,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -182,10 +183,10 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
return array, err
}
if v, ok := any.(localinterface.IFloats); ok {
return c.SliceFloat32(v.Floats(), option)
return c.SliceFloat32(v.Floats(), option...)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceFloat32(v.Interfaces(), option)
return c.SliceFloat32(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -197,7 +198,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
)
for i := 0; i < length; i++ {
f, err = c.Float32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = f
@ -209,7 +210,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
return []float32{}, err
}
f, err = c.Float32(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []float32{f}, err
@ -217,21 +218,22 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32
}
// SliceFloat64 converts `any` to []float64.
func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64, error) {
func (c *Converter) SliceFloat64(any interface{}, option ...SliceOption) ([]float64, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
f float64
array []float64 = nil
err error
f float64
array []float64 = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -240,7 +242,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -249,7 +251,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -258,7 +260,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -267,7 +269,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -276,7 +278,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -285,7 +287,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -299,7 +301,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -316,7 +318,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
}
if utils.IsNumeric(value) {
f, err = c.Float64(value)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []float64{f}, err
@ -325,7 +327,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -334,7 +336,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -343,7 +345,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -352,7 +354,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -361,7 +363,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -372,7 +374,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = f
@ -385,7 +387,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
return v.Floats(), err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceFloat64(v.Interfaces(), option)
return c.SliceFloat64(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -397,7 +399,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
)
for i := 0; i < length; i++ {
f, err = c.Float64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = f
@ -409,7 +411,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64
return []float64{}, err
}
f, err = c.Float64(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []float64{f}, err

View File

@ -17,21 +17,22 @@ import (
)
// SliceInt converts `any` to []int.
func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
func (c *Converter) SliceInt(any any, option ...SliceOption) ([]int, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ii int
array []int = nil
err error
ii int
array []int = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -85,7 +86,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
}
if utils.IsNumeric(value) {
ii, err = c.Int(value)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []int{ii}, err
@ -118,7 +119,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -127,7 +128,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -136,7 +137,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -145,7 +146,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -158,7 +159,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
return v.Ints(), err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceInt(v.Interfaces(), option)
return c.SliceInt(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -170,7 +171,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
)
for i := 0; i < length; i++ {
ii, err = c.Int(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = ii
@ -182,7 +183,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
return []int{}, err
}
ii, err = c.Int(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []int{ii}, err
@ -190,21 +191,22 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
}
// SliceInt32 converts `any` to []int32.
func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
func (c *Converter) SliceInt32(any any, option ...SliceOption) ([]int32, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ii int32
array []int32 = nil
err error
ii int32
array []int32 = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -258,7 +260,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
}
if utils.IsNumeric(value) {
ii, err = c.Int32(value)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []int32{ii}, err
@ -291,7 +293,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -300,7 +302,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -309,7 +311,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -318,7 +320,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -328,10 +330,10 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
return array, err
}
if v, ok := any.(localinterface.IInts); ok {
return c.SliceInt32(v.Ints(), option)
return c.SliceInt32(v.Ints(), option...)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceInt32(v.Interfaces(), option)
return c.SliceInt32(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -343,7 +345,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
)
for i := 0; i < length; i++ {
ii, err = c.Int32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = ii
@ -355,7 +357,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
return []int32{}, err
}
ii, err = c.Int32(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []int32{ii}, err
@ -363,21 +365,22 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
}
// SliceInt64 converts `any` to []int64.
func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
func (c *Converter) SliceInt64(any any, option ...SliceOption) ([]int64, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ii int64
array []int64 = nil
err error
ii int64
array []int64 = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -431,7 +434,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
}
if utils.IsNumeric(value) {
ii, err = c.Int64(value)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []int64{ii}, err
@ -464,7 +467,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -473,7 +476,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -482,7 +485,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -491,7 +494,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ii
@ -501,10 +504,10 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
return array, err
}
if v, ok := any.(localinterface.IInts); ok {
return c.SliceInt64(v.Ints(), option)
return c.SliceInt64(v.Ints(), option...)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceInt64(v.Interfaces(), option)
return c.SliceInt64(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -516,7 +519,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
)
for i := 0; i < length; i++ {
ii, err = c.Int64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = ii
@ -528,7 +531,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
return []int64{}, err
}
ii, err = c.Int64(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []int64{ii}, err

View File

@ -8,9 +8,22 @@ package converter
import "github.com/gogf/gf/v2/internal/json"
// SliceMapOption is the option for SliceMap function.
type SliceMapOption struct {
SliceOption SliceOption
MapOption MapOption
}
func (c *Converter) getSliceMapOption(option ...SliceMapOption) SliceMapOption {
if len(option) > 0 {
return option[0]
}
return SliceMapOption{}
}
// 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 *Converter) SliceMap(value any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) {
func (c *Converter) SliceMap(value any, option ...SliceMapOption) ([]map[string]any, error) {
if value == nil {
return nil, nil
}
@ -39,7 +52,8 @@ func (c *Converter) SliceMap(value any, sliceOption SliceOption, mapOption MapOp
return r, nil
default:
array, err := c.SliceAny(value, sliceOption)
sliceMapOption := c.getSliceMapOption(option...)
array, err := c.SliceAny(value, sliceMapOption.SliceOption)
if err != nil {
return nil, err
}
@ -48,8 +62,8 @@ func (c *Converter) SliceMap(value any, sliceOption SliceOption, mapOption MapOp
}
list := make([]map[string]any, len(array))
for k, v := range array {
m, err := c.Map(v, mapOption)
if err != nil && !sliceOption.ContinueOnError {
m, err := c.Map(v, sliceMapOption.MapOption)
if err != nil && !sliceMapOption.SliceOption.ContinueOnError {
return nil, err
}
list[k] = m

View File

@ -16,21 +16,22 @@ import (
)
// SliceStr converts `any` to []string.
func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, error) {
func (c *Converter) SliceStr(any interface{}, option ...SliceOption) ([]string, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
s string
array []string = nil
err error
s string
array []string = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -39,7 +40,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -48,7 +49,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -57,7 +58,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -66,7 +67,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -75,7 +76,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -89,7 +90,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -110,7 +111,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -119,7 +120,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -128,7 +129,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -137,7 +138,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -146,7 +147,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -155,7 +156,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -164,7 +165,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -175,7 +176,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = s
@ -188,7 +189,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
return v.Strings(), err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceStr(v.Interfaces(), option)
return c.SliceStr(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -200,7 +201,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
)
for i := 0; i < length; i++ {
s, err = c.String(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = s
@ -212,7 +213,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err
return []string{}, err
}
s, err = c.String(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []string{s}, err

View File

@ -17,21 +17,22 @@ import (
)
// SliceUint converts `any` to []uint.
func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, error) {
func (c *Converter) SliceUint(any interface{}, option ...SliceOption) ([]uint, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ui uint
array []uint = nil
err error
ui uint
array []uint = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -80,7 +81,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
}
if utils.IsNumeric(value) {
ui, err = c.Uint(value)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []uint{ui}, err
@ -113,7 +114,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -122,7 +123,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -131,7 +132,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -140,7 +141,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -156,7 +157,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
return v.Uints(), err
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceUint(v.Interfaces(), option)
return c.SliceUint(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -168,7 +169,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
)
for i := 0; i < length; i++ {
ui, err = c.Uint(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = ui
@ -180,7 +181,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
return []uint{}, err
}
ui, err = c.Uint(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []uint{ui}, err
@ -188,21 +189,22 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro
}
// SliceUint32 converts `any` to []uint32.
func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, error) {
func (c *Converter) SliceUint32(any interface{}, option ...SliceOption) ([]uint32, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ui uint32
array []uint32 = nil
err error
ui uint32
array []uint32 = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -254,7 +256,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
}
if utils.IsNumeric(value) {
ui, err = c.Uint32(value)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []uint32{ui}, err
@ -284,7 +286,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -293,7 +295,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -302,7 +304,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -311,7 +313,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -323,10 +325,10 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
// Default handler.
if v, ok := any.(localinterface.IUints); ok {
return c.SliceUint32(v.Uints(), option)
return c.SliceUint32(v.Uints(), option...)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceUint32(v.Interfaces(), option)
return c.SliceUint32(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -338,7 +340,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
)
for i := 0; i < length; i++ {
ui, err = c.Uint32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = ui
@ -350,7 +352,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
return []uint32{}, err
}
ui, err = c.Uint32(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []uint32{ui}, err
@ -358,21 +360,22 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32,
}
// SliceUint64 converts `any` to []uint64.
func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, error) {
func (c *Converter) SliceUint64(any interface{}, option ...SliceOption) ([]uint64, error) {
if empty.IsNil(any) {
return nil, nil
}
var (
err error
ui uint64
array []uint64 = nil
err error
ui uint64
array []uint64 = nil
sliceOption = c.getSliceOption(option...)
)
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.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -424,7 +427,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64,
}
if utils.IsNumeric(value) {
ui, err = c.Uint64(value)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []uint64{ui}, err
@ -454,7 +457,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64,
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -463,7 +466,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64,
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -472,7 +475,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64,
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -481,7 +484,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64,
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
array[k] = ui
@ -492,10 +495,10 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64,
}
// Default handler.
if v, ok := any.(localinterface.IUints); ok {
return c.SliceUint64(v.Uints(), option)
return c.SliceUint64(v.Uints(), option...)
}
if v, ok := any.(localinterface.IInterfaces); ok {
return c.SliceUint64(v.Interfaces(), option)
return c.SliceUint64(v.Interfaces(), option...)
}
// Not a common type, it then uses reflection for conversion.
originValueAndKind := reflection.OriginValueAndKind(any)
@ -507,7 +510,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64,
)
for i := 0; i < length; i++ {
ui, err = c.Uint64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
slice[i] = ui
@ -519,7 +522,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64,
return []uint64{}, err
}
ui, err = c.Uint64(any)
if err != nil && !option.ContinueOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
return []uint64{ui}, err

View File

@ -32,8 +32,15 @@ type StructOption struct {
ContinueOnError bool
}
func (c *Converter) getStructOption(option ...StructOption) StructOption {
if len(option) > 0 {
return option[0]
}
return StructOption{}
}
// Struct is the core internal converting function for any data to struct.
func (c *Converter) Struct(params, pointer any, option StructOption) (err error) {
func (c *Converter) Struct(params, pointer any, option ...StructOption) (err error) {
if params == nil {
// If `params` is nil, no conversion.
return nil
@ -63,6 +70,7 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error)
}()
var (
structOption = c.getStructOption(option...)
paramsReflectValue reflect.Value
paramsInterface any // DO NOT use `params` directly as it might be type `reflect.Value`
pointerReflectValue reflect.Value
@ -105,9 +113,13 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error)
}
// custom convert.
if ok, err = c.callCustomConverter(paramsReflectValue, pointerReflectValue); ok {
ok, err = c.callCustomConverter(paramsReflectValue, pointerReflectValue)
if err != nil && !structOption.ContinueOnError {
return err
}
if ok {
return nil
}
// Normal unmarshalling interfaces checks.
if ok, err = bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok {
@ -142,7 +154,7 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error)
// paramsMap is the map[string]any type variable for params.
// DO NOT use MapDeep here.
paramsMap, err = c.doMapConvert(paramsInterface, RecursiveTypeAuto, true, MapOption{
ContinueOnError: option.ContinueOnError,
ContinueOnError: structOption.ContinueOnError,
})
if err != nil {
return err
@ -161,7 +173,7 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error)
}
// Get struct info from cache or parse struct and cache the struct info.
cachedStructInfo := c.internalConverter.GetCachedStructInfo(
pointerElemReflectValue.Type(), option.PriorityTag,
pointerElemReflectValue.Type(), structOption.PriorityTag,
)
// Nothing to be converted.
if cachedStructInfo == nil {
@ -182,7 +194,7 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error)
// Firstly, search according to custom mapping rules.
// If a possible direct assignment is found, reduce the number of subsequent map searches.
for paramKey, fieldName := range option.ParamKeyToAttrMap {
for paramKey, fieldName := range structOption.ParamKeyToAttrMap {
paramsValue, ok = paramsMap[paramKey]
if !ok {
continue
@ -194,13 +206,13 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error)
cachedFieldInfo,
fieldValue,
paramsValue,
option,
structOption,
); err != nil {
return err
}
if len(cachedFieldInfo.OtherSameNameField) > 0 {
if err = c.setOtherSameNameField(
cachedFieldInfo, paramsValue, pointerReflectValue, option,
cachedFieldInfo, paramsValue, pointerReflectValue, structOption,
); err != nil {
return err
}
@ -215,7 +227,7 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error)
return c.bindStructWithLoopFieldInfos(
paramsMap, pointerElemReflectValue,
usedParamsKeyOrTagNameMap, cachedStructInfo,
option,
structOption,
)
}

View File

@ -13,6 +13,19 @@ import (
"github.com/gogf/gf/v2/errors/gerror"
)
// StructsOption is the option for Structs function.
type StructsOption struct {
SliceOption SliceOption
StructOption StructOption
}
func (c *Converter) getStructsOption(option ...StructsOption) StructsOption {
if len(option) > 0 {
return option[0]
}
return StructsOption{}
}
// Structs converts any slice to given struct slice.
//
// It automatically checks and converts json string to []map if `params` is string/[]byte.
@ -20,9 +33,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(
params any, pointer any, sliceOption SliceOption, structOption StructOption,
) (err error) {
func (c *Converter) Structs(params any, pointer any, option ...StructsOption) (err error) {
defer func() {
// Catch the panic, especially the reflection operation panics.
if exception := recover(); exception != nil {
@ -47,9 +58,10 @@ func (c *Converter) Structs(
}
// Converting `params` to map slice.
var (
paramsList []any
paramsRv = reflect.ValueOf(params)
paramsKind = paramsRv.Kind()
paramsList []any
paramsRv = reflect.ValueOf(params)
paramsKind = paramsRv.Kind()
structsOption = c.getStructsOption(option...)
)
for paramsKind == reflect.Ptr {
paramsRv = paramsRv.Elem()
@ -62,8 +74,11 @@ func (c *Converter) Structs(
paramsList[i] = paramsRv.Index(i).Interface()
}
default:
paramsMaps, err := c.SliceMap(params, sliceOption, MapOption{
ContinueOnError: structOption.ContinueOnError,
paramsMaps, err := c.SliceMap(params, SliceMapOption{
SliceOption: structsOption.SliceOption,
MapOption: MapOption{
ContinueOnError: structsOption.StructOption.ContinueOnError,
},
})
if err != nil {
return err
@ -95,7 +110,7 @@ func (c *Converter) Structs(
if !tempReflectValue.IsValid() {
tempReflectValue = reflect.New(itemType.Elem()).Elem()
}
if err = c.Struct(paramsList[i], tempReflectValue, structOption); err != nil {
if err = c.Struct(paramsList[i], tempReflectValue, structsOption.StructOption); err != nil {
return err
}
reflectElemArray.Index(i).Set(tempReflectValue.Addr())
@ -109,7 +124,7 @@ func (c *Converter) Structs(
} else {
tempReflectValue = reflect.New(itemType).Elem()
}
if err = c.Struct(paramsList[i], tempReflectValue, structOption); err != nil {
if err = c.Struct(paramsList[i], tempReflectValue, structsOption.StructOption); err != nil {
return err
}
reflectElemArray.Index(i).Set(tempReflectValue)

View File

@ -8,9 +8,12 @@
package structcache
import (
"context"
"reflect"
"runtime"
"sync"
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
@ -36,6 +39,7 @@ type Converter struct {
}
// AnyConvertFunc is the function type for converting any to specified type.
// Note that the parameter `to` is usually a pointer type.
type AnyConvertFunc func(from any, to reflect.Value) error
// NewConverter creates and returns a new Converter object.
@ -56,21 +60,39 @@ func (cf *Converter) MarkTypeConvertFunc(fieldType reflect.Type) {
}
// RegisterAnyConvertFunc registers custom type converting function for specified type.
func (cf *Converter) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) {
if t == nil || convertFunc == nil {
func (cf *Converter) RegisterAnyConvertFunc(dstType reflect.Type, convertFunc AnyConvertFunc) {
if dstType == nil || convertFunc == nil {
return
}
for t.Kind() == reflect.Ptr {
t = t.Elem()
for dstType.Kind() == reflect.Ptr {
dstType = dstType.Elem()
}
if t.Kind() == reflect.Interface {
if dstType.Kind() == reflect.Interface {
cf.interfaceToTypeConvertMap = append(cf.interfaceToTypeConvertMap, interfaceTypeConverter{
interfaceType: t,
interfaceType: dstType,
convertFunc: convertFunc,
})
return
}
cf.anyToTypeConvertMap[t] = convertFunc
cf.anyToTypeConvertMap[dstType] = convertFunc
intlog.Printf(
context.Background(),
`RegisterAnyConvertFunc: %s -> %s`,
dstType.String(), runtime.FuncForPC(reflect.ValueOf(convertFunc).Pointer()).Name(),
)
}
// GetAnyConvertFuncByType retrieves and returns the converting function for specified type.
func (cf *Converter) GetAnyConvertFuncByType(dstType reflect.Type) AnyConvertFunc {
if dstType.Kind() == reflect.Ptr {
dstType = dstType.Elem()
}
return cf.anyToTypeConvertMap[dstType]
}
// IsAnyConvertFuncEmpty checks whether there's any converting function registered.
func (cf *Converter) IsAnyConvertFuncEmpty() bool {
return len(cf.anyToTypeConvertMap) == 0
}
func (cf *Converter) checkTypeImplInterface(t reflect.Type) AnyConvertFunc {