json.Unmarshal 解码数字意外变为 float64 问题
2 min read
问题
使用 json.Unmarshal 解码数字类型到 any 类型时,会默认变为 float64,如:
func TestNumber(t *testing.T) {
jsonStruct := map[string]int64{"Int": 1}
jsonBytes, err := json.Marshal(jsonStruct)
if err != nil {
fmt.Println("marshal err:", err)
}
fmt.Println("jsonBytes:", string(jsonBytes)) // jsonBytes: {"Int":1}
var jsonDecodeStruct map[string]any
err = json.Unmarshal(jsonBytes, &jsonDecodeStruct)
if err != nil {
fmt.Println("unmarshal err:", err)
}
// dec := json.NewDecoder(bytes.NewReader(jsonBytes))
// dec.UseNumber()
// err = dec.Decode(&jsonDecodeStruct)
// if err != nil {
// fmt.Println("decode err:", err)
// }
fmt.Println("jsonDecodeStruct:", jsonDecodeStruct) // jsonDecodeStruct: map[Int:1]
fmt.Printf("Int type = %T\n", jsonDecodeStruct["Int"]) // Int type = float64
}
解决方案
使用注释的 json.NewDecoder 和 UseNumber 替换 json.Unmarshal 来解决。
类型会变为 json.Number,底层类型为 string。
这同样适用于 big.Int 类型,如:
func TestNumber(t *testing.T) {
bigInt := big.NewInt(0)
bigInt.SetString("144445436745653633243543634375134532532", 10)
jsonStruct := map[string]*big.Int{"Int": bigInt}
jsonBytes, err := json.Marshal(jsonStruct)
if err != nil {
fmt.Println("marshal err:", err)
}
fmt.Println("jsonBytes:", string(jsonBytes))
var jsonDecodeStruct map[string]any
dec := json.NewDecoder(bytes.NewReader(jsonBytes))
dec.UseNumber()
err = dec.Decode(&jsonDecodeStruct)
if err != nil {
fmt.Println("decode err:", err)
}
fmt.Println("jsonDecodeStruct:", jsonDecodeStruct)
fmt.Printf("Int type = %T\n", jsonDecodeStruct["Int"])
}
类型同样是 json.Number。