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
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 |
|
}) |
|
}
|
|
|