今天线上出现了一个很奇怪的问题,简单讲就是某个比较通用的服务反序列化 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 的精度问题,210410791428449262.104107914284493e+16 的形式记录起来!

也就是最后得到的 21041079142844930 这个数字。

所以,最好别用 interface{} !如果你真的要用,对于数字类型要多加小心。

暂无评论