You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

58 lines
1.6 KiB

package codec
import (
"reflect"
"strconv"
"strings"
"github.com/bytedance/sonic"
"github.com/go-viper/mapstructure/v2"
)
func MapDecode(input, output any) (err error) {
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Result: output,
WeaklyTypedInput: true, // 开启弱类型转换
DecodeHook: mapstructure.ComposeDecodeHookFunc(StringToNumberHook()),
})
if err != nil {
return
}
err = decoder.Decode(input)
return
}
// 方案1:最推荐 - 字符串 → 数字(int/uint/float)全覆盖
func StringToNumberHook() mapstructure.DecodeHookFunc {
return mapstructure.DecodeHookFuncType(func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
if from.Kind() == reflect.String {
str := data.(string)
str = strings.TrimSpace(str)
switch to.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.ParseInt(str, 10, 64)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.ParseUint(str, 10, 64)
case reflect.Float32, reflect.Float64:
return strconv.ParseFloat(str, 64)
}
// string to []float64, [][]float64
if to.Kind() == reflect.Slice {
switch to {
case reflect.SliceOf(reflect.TypeOf(float64(0.0))):
var v []float64
if err := sonic.UnmarshalString(str, &v); err == nil {
return v, nil
}
case reflect.SliceOf(reflect.SliceOf(reflect.TypeOf(float64(0.0)))):
var v [][]float64
if err := sonic.UnmarshalString(str, &v); err == nil {
return v, nil
}
}
}
}
return data, nil
})
}