You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JSON数字Unmarshal至interface{}后截断,如何解决数值失真问题?

问题

我有一个包含多字段的JSON,按照Stack Overflow《How effectively to change JSON keys》里的方法循环处理删除不需要的键后,原有JSON的数值出现了变化——部分变成浮点数,原本的1684366653200744506被截断成了1684366653200744400。演示输出如下:

2009/11/10 23:00:00 1684366653200744448.000000
2009/11/10 23:00:00 map[timestamp:1.6843666532007444e+18]
2009/11/10 23:00:00 json Marshal from maps of key string and value interface to batch json for insert to DB
2009/11/10 23:00:00 {"timestamp":1684366653200744400}

想搞清楚:

  • 为什么数值会被截断?
  • 是不是interface{}导致的这个问题?
  • 怎么改才能避免这种情况?
分析与解决方法

原因说明

  1. 浮点数精度限制:Go的encoding/json库默认解析JSON时,若用interface{}接收整数,会自动转成float64类型。但float64的有效精度只有53位,你那个19位的整数远超出这个范围,存储时只能做近似处理,自然就被截断了。
  2. 和interface{}的关系:不是interface{}本身有问题,而是当你用map[string]interface{}存储解析后的JSON数据时,整数会被默认转成float64,后续序列化输出的就是近似后的数值。

解决办法

1. 用结构体替代map[string]interface{}

定义一个和JSON结构匹配的结构体,把需要的字段类型指定为int64(或uint64,根据数值范围选择),这样解析时会直接保留整数类型,不会转成浮点数。示例代码:

type Data struct {
    Timestamp int64 `json:"timestamp"`
    // 其他需要保留的字段
}

var data Data
err := json.Unmarshal(rawJSON, &data)
// 后续处理这个结构体即可,序列化时数值不会丢失精度

2. 使用json.Number类型

解析JSON时,开启UseNumber()选项,让整数以json.Number类型存储(本质是字符串),避免转成浮点数。示例:

var result map[string]interface{}
decoder := json.NewDecoder(strings.NewReader(rawJSON))
decoder.UseNumber()
err := decoder.Decode(&result)

// 需要使用数值时,将json.Number转为int64
timestamp, err := result["timestamp"].(json.Number).Int64()

3. 自定义JSON解析逻辑

如果需要动态处理字段(比如删除不需要的键),可以用json.RawMessage保留原始JSON片段,处理完成后再解析成对应类型,以此避免精度丢失。


内容的提问来源于stack exchange,提问作者echo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 17:53:16