【注意】最后更新于 April 19, 2021,文中内容可能已过时,请谨慎使用。
一次偶然的情况, 使用encoding/json
的 Unmarshal
处理 int 类型字段时会被处理成 float64,且使用科学记数法展示
我们先组一个数据:
1
2
3
4
5
6
|
{
"uid": 14625461,
"ad_type": 21,
"sys": 1,
"hospital_id": "108720"
}
|
直接使用 Unmarshal
处理
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
|
// JsonDecode 通用的 json 解析方法
func JsonDecode(raw string, tpl interface{}, useNumber bool) error {
if useNumber {
d := json.NewDecoder(bytes.NewReader([]byte(raw)))
d.UseNumber()
return d.Decode(tpl)
}
return json.Unmarshal([]byte(raw), &tpl)
}
func TestDemo(t *testing.T) {
t.Log("start")
data := `
{
"uid": 14625461,
"ad_type": 21,
"sys": 1,
"hospital_id": "108720"
}
`
tpl := map[string]interface{}{}
JsonDecode(data, &tpl, false)
t.Logf("%#+v \n", tpl)
}
|
这时候输出:
1
|
map[string]interface {}{"ad_type":21, "hospital_id":"108720", "sys":1, "uid":1.4625461e+07}
|
本来应该正常显示的 uid 解析后的值变成了 1.4625461e+07
, 这种数据格式明细不符合我们的预期, 因此需要特殊处理一下, 按上面的例子:
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
|
// JsonDecode 通用的 json 解析方法
func JsonDecode(raw string, tpl interface{}, useNumber bool) error {
if useNumber {
d := json.NewDecoder(bytes.NewReader([]byte(raw)))
d.UseNumber()
return d.Decode(tpl)
}
return json.Unmarshal([]byte(raw), &tpl)
}
func TestDemo(t *testing.T) {
t.Log("start")
data := `
{
"uid": 14625461,
"ad_type": 21,
"sys": 1,
"hospital_id": "108720"
}
`
tpl := map[string]interface{}{}
JsonDecode(data, &tpl, true)
t.Logf("%#+v \n", tpl)
}
|
此时输出:
1
|
map[string]interface {}{"ad_type":"21", "hospital_id":"108720", "sys":"1", "uid":"14625461"}
|
关键代码就在:
1
2
3
4
5
|
d := json.NewDecoder(bytes.NewReader([]byte(raw)))
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
// Number instead of as a float64.
d.UseNumber() // 这里是关键
return d.Decode(tpl)
|
这里再追一下上层代码, 发现到这个函数里面:
1
2
3
4
5
6
7
8
9
10
11
12
|
// 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
}
|
这里如果不设置d.UseNumber()
将会把数字类型转换成 float64
格式的, 如果设置了, 就变成了 json.Number
格式的, 底层是 string 类型
基于这个情况,在处理 json 数据时需要多一层考虑,使用 str := rawValue.(json.Number).String()
把 interface{}
的转成 string
类型, 然后再考虑是否转成 int
类型, 代码如下:
1
2
|
str := rawValue.(json.Number).String()
intValue, err = strconv.Atoi(str)
|
文章作者
GPF
上次更新
2021-04-19
(d2b4f64)