解决Go encoding/json 将JSON大数字解析为浮点数的问题


解决Go encoding/json 将JSON大数字解析为浮点数的问题

go语言在处理json中的大整数时,默认行为可能导致精度丢失,将其解析为浮点数。本文将深入探讨这一问题,并提供一种专业且可靠的解决方案:利用`json.decoder`的`usenumber()`方法,将数字类型解析为`json.number`字符串,从而有效避免数据类型转换带来的精度问题,确保json数据在go程序中精确地序列化与反序列化。

Go语言JSON处理中的数字类型转换问题

在使用Go语言的encoding/json包进行JSON数据的序列化(Marshal)和反序列化(Unmarshal)时,如果目标类型是interface{},json包会尝试将JSON中的数字类型自动转换为Go的float64类型。对于不带小数点的整数,尤其是当它们的数值较大时,这种自动转换可能导致数据以科学计数法表示,或者更严重地,由于浮点数的精度限制而丢失原始数值的精确性。

例如,考虑以下JSON字符串:

{
    "id": 12423434,
    "Name": "Fernando"
}

当使用json.Unmarshal将其反序列化到一个interface{}类型的变量,再将其断言为map[string]interface{}时,id字段的值会被解析为float64。随后,如果再次将其序列化回JSON字符串,id字段可能会以浮点数形式(例如1.2423434e+07)出现,从而改变了原始数据的表示形式。

以下是导致此问题的示例代码:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

func main() {
    // 原始JSON字符串
    var b = []byte(`
        {
        "id": 12423434,
        "Name": "Fernando"
        }
    `)

    // 反序列化到 interface{}
    var f interface{}
    json.Unmarshal(b, &f)

    // 断言为 map[string]interface{}
    m := f.(map[string]interface{})

    // 打印map,可见id已变为浮点数
    fmt.Println("反序列化后的map:", m)

    // 再次序列化map到JSON
    result, _ := json.Marshal(m)

    // 打印结果,id以浮点数形式出现
    os.Stdout.Write([]byte("再次序列化后的JSON: "))
    os.Stdout.Write(result)
    fmt.Println()
}

运行上述代码,输出结果将类似:

反序列化后的map: map[id:1.2423434e+07 Name:Fernando]
再次序列化后的JSON: {"Name":"Fernando","id":1.2423434e+07}

这清楚地表明,id字段的整数值在反序列化过程中被转换为了浮点数。

解决方案:使用 json.Decoder.UseNumber()

为了解决这个问题,并确保JSON中的数字(尤其是大整数)在Go程序中能够保持其原始的精确表示,我们可以利用encoding/json包提供的json.Decoder的UseNumber()方法。

UseNumber()方法会改变json.Decoder的默认行为:当遇到JSON中的数字时,它不再将其解析为float64,而是将其解析为json.Number类型。json.Number是一个字符串类型,它存储了数字的原始字符串表示形式。这样,无论数字有多大或多长,它的精确值都不会因浮点数转换而丢失。

Viggle AI Video Viggle AI Video

Powerful AI-powered animation tool and image-to-video AI generator.

Viggle AI Video 115 查看详情 Viggle AI Video

以下是使用UseNumber()方法的示例代码:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strings"
)

var data = `{
    "id": 12423434,
    "Name": "Fernando"
}`

func main() {
    // 创建一个 json.Decoder
    d := json.NewDecoder(strings.NewReader(data))

    // 启用 UseNumber(),使数字解析为 json.Number 类型
    d.UseNumber()

    var x interface{}
    // 使用 Decoder 进行反序列化
    if err := d.Decode(&x); err != nil {
        log.Fatal(err)
    }

    // 打印反序列化后的结果,可见id现在是 json.Number 类型(字符串表示)
    fmt.Printf("反序列化到 %#v\n", x)

    // 再次序列化回JSON
    result, err := json.Marshal(x)
    if err != nil {
        log.Fatal(err)
    }

    // 打印再次序列化后的JSON,id保持了原始整数形式
    fmt.Printf("再次序列化到 %s\n", result)
}

运行上述代码,输出结果将是:

反序列化到 map[string]interface {}{"id":"12423434", "Name":"Fernando"}
再次序列化到 {"Name":"Fernando","id":12423434}

从输出可以看出,id字段现在被正确地保持为整数形式,没有被转换为浮点数或科学计数法。

json.Number 的作用与优势

json.Number类型是一个string的别名,它在内部存储了JSON中数字的原始文本表示。当UseNumber()被启用后,所有JSON数字都会被解码成json.Number。

优势:

  1. 精度保持: 彻底避免了float64可能带来的精度丢失问题,对于需要处理精确大整数(如数据库ID、金融交易金额等)的场景至关重要。
  2. 灵活性: 即使在不知道JSON结构,必须使用interface{}进行反序列化的情况下,也能保证数字的精确性。
  3. 类型转换控制: 在获取json.Number后,你可以根据实际需求将其安全地转换为int64、float64甚至big.Int,而不是在反序列化阶段被强制转换为float64。json.Number提供了Int64()和Float64()等方法进行安全的类型转换。

例如,如果你想将json.Number转换为int64,可以这样做:

// 假设 m 是反序列化后的 map[string]interface{}
// 在启用UseNumber()后,x 会被解码为 map[string]interface{}
// 我们可以这样访问其元素:
if decodedMap, ok := x.(map[string]interface{}); ok {
    if val, ok := decodedMap["id"].(json.Number); ok {
        idInt, err := val.Int64()
        if err != nil {
            log.Fatalf("无法将id转换为int64: %v", err)
        }
        fmt.Printf("id (int64): %d\n", idInt)
    }
}

注意事项与最佳实践

  1. json.Decoder 的使用: UseNumber()是json.Decoder的一个方法,这意味着你需要显式地创建一个json.Decoder实例来处理输入流,而不是直接使用json.Unmarshal()函数。
  2. 后续类型断言: 当你使用UseNumber()后,反序列化到interface{}中的数字类型将是json.Number。因此,在访问这些字段时,你需要进行相应的类型断言。
  3. 性能考量: 对于极度性能敏感的场景,如果JSON结构已知且数字范围在int64或float64可表示的范围内,直接定义结构体进行反序列化通常是最高效的方式。UseNumber()主要用于结构未知或需要处理超大整数的情况。
  4. 错误处理: 从json.Number转换为其他数字类型(如Int64()或Float64())时,务必检查返回的错误,以处理潜在的溢出或格式不匹配情况。

总结

Go语言的encoding/json包在处理JSON数字时,默认将它们解析为float64,这可能导致大整数的精度问题。通过使用json.Decoder的UseNumber()方法,我们可以将这些数字作为json.Number类型(其原始字符串表示)进行反序列化,从而彻底避免精度丢失。这种方法在处理未知JSON结构或需要精确表示大整数的场景中尤为重要。理解并正确运用UseNumber(),将有助于构建更健壮、数据更精确的Go应用程序。

以上就是解决Go encoding/json 将JSON大数字解析为浮点数的问题的详细内容,更多请关注其它相关文章!


# json  # 创建一个  # 将是  # 我们可以  # 尤其是  # 是一个  # 转换为  # 将其  # 浮点数  # 序列化  # json处理  # 金融  # ai  # go语言  # go  # js  # AI-powered  # 宣城网站优化公司有哪些  # 石家庄数字营销推广公司  # seo560  # 阜阳网站优化哪家专业  # 网络营销推广方向有哪些  # seo排名第一的工具seo博客  # 电子商务里的seo  # 营销推广全网整合营销  # 单位网站建设哪个好  # 西乡怎么找网站优化 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 抖音怎么解除第三方绑定_抖音解除第三方平台绑定方法介绍  CDR如何复制交互式填充色  Excel怎么用XLOOKUP函数实现双向查找_ExcelXLOOKUP替代VLOOKUP+HLOOKUP的高级用法  悟空浏览器网页版在线工具 悟空浏览器网页版在线平台入口  西瓜视频怎么查看访客记录_西瓜视频访客记录查看方法  2025考研成绩查询时间入口分享  漫蛙漫画直连入口 _ manwa官方备用入口实时检测  热血江湖归来医师加点攻略  Excel如何设置动态下拉菜单_Excel表格下拉选项快速方法  优化Google Charts Gauge:在数据库无数据时显示默认值  鸣潮历史学家灯塔位置一览  《磁力猫》最好用的磁官网  Windows自带的便笺数据如何备份_防止数据丢失的便利贴迁移教程【干货】  Safari浏览器自动填表功能失效怎么办 Safari表单管理修复  菜鸟裹裹怎样获得取件码_菜鸟裹裹获得取件码步骤  《盗墓笔记手游》技能介绍  XPath动态元素定位:如何精准选择文本内容变化的元素  苹果如何下载nanobanana  智慧团建活动报名入口 智慧团建活动报名入口手机端官网​  路由器DNS怎么设置最快 优化DNS提升上网速度教程  键盘声音异常怎么回事_键盘异响怎么处理  Excel如何快速找到并断开外部数据源链接_Excel外部数据源断开方法  Win10怎么设置快速启动 Win10开启快速启动设置方法  Flexbox布局:实现粘性导航与底部页脚的完美结合  荣耀Magic6 Pro拍照成像偏暗_荣耀Magic6 Pro夜景优化  申通快件单号查询平台 申通包裹物流动态跟踪  Mac如何开启画中画模式_Mac Safari浏览器视频画中画功能  php如何实现多域名共享session_php存储session到redis与跨域读取配置  苹果手机缓存怎么清除_苹果手机缓存如何清除iphone各版本操作步骤  J*aScript包管理器_Npm与Yarn对比  VS Code源代码管理(SCM)视图的进阶使用技巧  《偃武》甘宁技能详解  在PHP环境中正确加载HTML资源:CSS样式与图片路径指南  疯狂小鸟微信小游戏入口 疯狂小鸟网页版秒玩  电脑“无法访问指定设备、路径或文件”怎么办?五种权限设置方法  抖音网页版地址直接进入_抖音网页版在线观看入口  J*a中导出MySQL表为SQL脚本的两种方法  firefox火狐浏览器最新官网主页_ firefox火狐浏览器平台入口直达官方链接  PHP与SQL实践:高效实现数据复制与特定列值修改  铁路12306买票怎么选双人铺 铁路12306卧铺分配规则说明  斯宾塞称XGP云游戏“蒸蒸日上”:正在构建一个游戏从未如此唾手可得的未来  QQ邮箱手机版网页版 QQ邮箱登录入口地址  yy漫画登录页面官方入口_yy漫画在线阅读网址入口  PyEZ 配置提交中 RpcTimeoutError 的健壮性处理策略  抖音如何解除|直播|权限绑定_抖音关闭并解绑|直播|功能的方法  《腾讯相册管家》注销账号方法  猫眼电影app如何参与官方的抽奖活动_猫眼电影官方抽奖参与方法  谷歌浏览器如何查找和删除恶意软件 谷歌浏览器内置安全清理工具使用教程  Go语言反射机制:如何访问被嵌入结构体遮蔽的方法  vivo手机视频通话美颜怎么设置_vivo视频通话美颜开启方法 

 2025-11-29

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.