json反序列化 int64丢失
# 问题分析
json数据反序列化时,在遇到定义中是interface{}时,对于数字类型,会转化成float64类型,从而导致如果数字类型的精度损失。查看json.Unmarshal源码发现下面代码片段
// convertNumber converts the number literal s to a float64 or a Number
// depending on the setting of d.useNumber.
func (d *decodeState) convertNumber(s string) (interface{}, error) {
if d.useNumber {
return Number(s), nil
}
f, err := strconv.ParseFloat(s, 64)
if err != nil {
return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)}
}
return f, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 代码片段
从代码中可见,在未设置 useNumber 时,默认对数字转化成了float64。从而可以通过设置 useNumber,解决精度丢失问题。示例代码如下
package main
import (
"bytes"
"encoding/json"
"fmt"
"testing"
)
type UserData struct {
Value interface{} `json:"value"`
}
func TestName(t *testing.T) {
data := &UserData{
Value: 1<<63 - 1,
}
dataBytes, _ := json.Marshal(data)
fmt.Println("json data: ", string(dataBytes))
dataUnmarshal := &UserData{}
dec := json.NewDecoder(bytes.NewBuffer(dataBytes))
dec.UseNumber()
_ = dec.Decode(dataUnmarshal)
fmt.Println("json unmarshal use number: ", dataUnmarshal.Value)
_ = json.Unmarshal(dataBytes, dataUnmarshal)
fmt.Printf(fmt.Sprintf("json unmarshal normal: %v", dataUnmarshal.Value))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
输出结果如下
=== RUN TestName
json data: {"value":9223372036854775807}
json unmarshal use number: 9223372036854775807
json unmarshal normal: 9.223372036854776e+18--- PASS: TestName (0.00s)
PASS
1
2
3
4
5
2
3
4
5
编辑 (opens new window)
上次更新: 2023/02/24, 10:34:03