今天线上出现了一个很奇怪的问题,简单讲就是某个比较通用的服务反序列化 JSON 的时候,发现有些 int64 的 ID 解开之后不是预期的数字。
废话不多说!直接上代码!不看答案,你能知道输出什么吗?
package main
import (
"encoding/json"
"fmt"
"log"
"sync"
"time"
)
type Msg struct {
DrId int `json:"drid"`
}
type Data struct {
Msg interface{} `json:"msg"`
}
func main() {
msg := Msg{DrId: 21041079142844926}
data := Data{Msg: msg}
str2, _ := json.Marshal(data)
// 1. {"msg":{"drid":21041079142844926}}
fmt.Println(string(str2))
var data2 Data
_ = json.Unmarshal(str2, &data2)
// fmt.Println(data2)
str3, _ := json.Marshal(data2)
// 2. ?
fmt.Println(string(str3))
}
OK,揭晓答案:
1 和 2 打印的结果不一样:
{"msg":{"drid":21041079142844926}}
{"msg":{"drid":21041079142844930}}
是不是很懵逼?
懵逼就对了,上面的注释打开,你会看到这样的输出:
{map[drid:2.104107914284493e+16]}
也就是说,interface{}
装了一个 map[string]interface{}
!
但是!
json.Unmarshal
的时候,drid
被认为是一个数字,此时就用 float64
保存了 21041079142844926
!
而又因为 float64
的精度问题,21041079142844926
以 2.104107914284493e+16
的形式记录起来!
也就是最后得到的 21041079142844930
这个数字。
所以,最好别用 interface{}
!如果你真的要用,对于数字类型要多加小心。