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