新闻中心
Golang中如何精确处理JSON大整数:json.Number的应用

在使用go语言的`encoding/json`包处理json数据时,当未预定义结构体而使用`interface{}`进行编解码时,长整数可能会被自动转换为浮点数,导致精度丢失或格式变化。本文将介绍如何通过`json.decoder`的`usenumber()`方法,将json中的数字解析为`json.number`类型,从而精确保留其原始字符串表示,有效解决大整数浮点化问题。
Go JSON编解码中长数字的浮点化问题
Go语言的encoding/json包在处理未指定具体类型的JSON数据时,通常会将JSON中的数字解析为Go的float64类型。当JSON中包含较大的整数(例如ID或时间戳)时,如果将其解码到interface{}类型,这些整数会被默认转换为float64。在随后的编码过程中,float64类型的数据可能会以科学计数法表示,或者在极端情况下损失精度,从而改变原始数字的精确表示。
考虑以下JSON字符串:
{
"id": 12423434,
"Name": "Fernando"
}如果使用json.Unmarshal将其解码到一个interface{},然后再次编码回JSON字符串,id字段可能会变成浮点数表示:
package main
import (
"encoding/json"
"fmt"
"os"
)
func main() {
// 原始JSON字符串
jsonString := []byte(`
{
"id": 12423434,
"Name": "Fernando"
}
`)
// 解码到 interface{}
var data interface{}
err := json.Unmarshal(jsonString, &data)
if err != nil {
fmt.Printf("Unmarshal error: %v\n", err)
return
}
// 此时 data 中的数字字段已是 float64 类型
// 打印解码后的 map
if m, ok := data.(map[string]interface{}); ok {
fmt.Printf("解码后的Map: %v\n", m)
}
// 再次编码回JSON字符串
result, err := json.Marshal(data)
if err != nil {
fmt.Printf("Marshal error: %v\n", err)
return
}
// 打印结果,id 字段变为浮点数表示
fmt.Printf("再次编码后的JSON: %s\n", result)
}运行上述代码,输出可能如下:
解码后的Map: map[Name:Fernando id:1.2423434e+07]
再次编码后的JSON: {"Name":"Fernando","id":1.2423434e+07}可以看到,原始的整数12423434在经过interface{}中转后,变成了1.2423434e+07,这通常不是我们期望的结果。
解决方案:使用json.Decoder.UseNumber()
为了解决这个问题,Go语言的encoding/json包提供了json.Number类型和json.Decoder的UseNumber()方法。
json.Number类型是一个字符串别名(type Number string),它用于存储JSON中数字的原始字符串表示。通过UseNumber()方法,我们可以指示json.Decoder在解码JSON时,将所有数字解析为json.Number类型,而不是默认的float64。这样,数字的精确值和原始格式就能得以保留。
以下是使用json.Decoder.UseNumber()来精确处理JSON数字的示例:
N世界
一分钟搭建会展元宇宙
138
查看详情
package main
import (
"encoding/json"
"fmt"
"log"
"strings"
)
func main() {
jsonString := `{
"id": 12423434,
"Name": "Fernando",
"large_id": 9223372036854775807,
"pi": 3.1415926535
}`
// 创建一个 json.Decoder
decoder := json.NewDecoder(strings.NewReader(jsonString))
// 调用 UseNumber() 方法,指示解码器将所有数字解析为 json.Number
decoder.UseNumber()
var data interface{}
if err := decoder.Decode(&data); err != nil {
log.Fatalf("解码失败: %v", err)
}
// 打印解码后的数据,此时数字字段为 json.Number 类型
fmt.Printf("解码后的数据类型: %#v\n", data)
// 遍历 map,检查数字类型
if m, ok := data.(map[string]interface{}); ok {
for k, v := range m {
if num, isNumber := v.(json.Number); isNumber {
fmt.Printf("字段 '%s' 是 json.Number 类型,值为: %s\n", k, num)
// 可以根据需要转换为 int64 或 float64
if i, err := num.Int64(); err == nil {
fmt.Printf(" -> 转换为 int64: %d\n", i)
}
if f, err := num.Float64(); err == nil {
fmt.Printf(" -> 转换为 float64: %f\n", f)
}
} else {
fmt.Printf("字段 '%s' 是其他类型,值为: %v\n", k, v)
}
}
}
// 再次编码回JSON字符串
result, err := json.Marshal(data)
if err != nil {
log.Fatalf("编码失败: %v", err)
}
// 打印再次编码后的JSON,数字字段将保持原始格式
fmt.Printf("再次编码后的JSON: %s\n", result)
}运行上述代码,输出将是:
解码后的数据类型: map[string]interface {}{"Name":"Fernando", "large_id":"9223372036854775807", "id":"12423434", "pi":"3.1415926535"}
字段 'Name' 是其他类型,值为: Fernando
字段 'large_id' 是 json.Number 类型,值为: 9223372036854775807
-> 转换为 int64: 9223372036854775807
-> 转换为 float64: 9223372036854775807.000000
字段 'id' 是 json.Number 类型,值为: 12423434
-> 转换为 int64: 12423434
-> 转换为 float64: 12423434.000000
字段 'pi' 是 json.Number 类型,值为: 3.1415926535
-> 转换为 float64: 3.141593
再次编码后的JSON: {"Name":"Fernando","id":12423434,"large_id":9223372036854775807,"pi":3.1415926535}从输出中可以看出,id、large_id和pi字段都被解析成了json.Number类型,并且在再次编码时,它们都保留了原始的数字格式,没有被转换为科学计数法或丢失精度。json.Number类型提供了Int64()和Float64()方法,允许我们在需要时安全地将其转换为具体的数值类型,并处理可能发生的转换错误。
json.Number的特性与应用场景
- 保留原始精度: json.Number以字符串形式存储数字,因此可以精确地保留任意大小的整数或浮点数,避免float64类型可能带来的精度问题。
- 灵活的类型转换: 虽然存储为字符串,但json.Number提供了Int64()、Float64()等方法,可以根据需要将其转换为Go的内置数值类型,并返回错误以处理无效转换。
-
适用场景:
- 当JSON结构不固定,无法预先定义Go结构体时。
- 处理包含非常大整数(超出int64范围或float64精度)的JSON数据时。
- 需要确保JSON数字在经过Go程序处理后,其字符串表示与原始输入完全一致的场景(例如,API网关的透明转发)。
- 在需要对数字进行严格类型检查或自定义验证时。
替代方案:预定义结构体
如果JSON数据的结构是已知的且稳定的,最推荐和直接的方法是定义一个Go结构体来精确映射JSON字段。对于可能出现大整数的字段,可以直接将其类型定义为int64或string,避免interface{}带来的默认浮点转换。
例如:
package main
import (
"encoding/json"
"fmt"
"log"
)
type User struct {
ID int64 `json:"id"` // 使用 int64 精确存储大整数
Name string `json:"Name"`
LargeID string `json:"large_id"` // 或者直接使用 string 来存储,如果数字太大 int64 也无法容纳
}
func main() {
jsonString := `{
"id": 12423434,
"Name": "Fernando",
"large_id": 9223372036854775807
}`
var user User
if err := json.Unmarshal([]byte(jsonString), &user); err != nil {
log.Fatalf("解码失败: %v", err)
}
fmt.Printf("解码后的结构体: %+v\n", user)
result, err := json.Marshal(user)
if err != nil {
log.Fatalf("编码失败: %v", err)
}
fmt.Printf("再次编码后的JSON: %s\n", result)
}这种方法在结构体明确时更为高效和类型安全。然而,当结构体不确定或需要处理极其庞大的数字时,json.Decoder.UseNumber()结合json.Number则提供了更强大的灵活性。
总结
在Go语言中处理JSON数据时,若需精确保留数字的原始表示,避免interface{}默认将大整数转换为float64而导致的精度或格式问题,可以根据具体场景选择不同的策略:
- 首选方案(结构体已知): 定义明确的Go结构体,将可能的大整数字段类型设置为int64或string。
- 动态方案(结构体未知): 使用json.NewDecoder().UseNumber()方法,将JSON中的所有数字解析为json.Number类型。这允许程序在运行时检查和转换数字,同时保持其原始字符串表示。
选择合适的策略能够确保JSON数据的完整性和准确性,尤其是在处理金融、科学计算或分布式系统中的标识符等对数字精度要求较高的场景。
以上就是Golang中如何精确处理JSON大整数:json.Number的应用的详细内容,更多请关注其它相关文章!
# 浮点数
# 做网站建设老师打电话
# 浙江省网站推广托管政策
# 网站建设 菜鸟教程
# 深夜商业推广网站
# 百度seo统计
# 北京网站排名优化哪家好
# 山东风机网站建设
# 金华湖南网站优化推广
# 网站维护优化方案怎么写
# 福田网站建设解决方案
# 编解码
# 是一个
# 资源管理
# js
# 可以根据
# 浮点
# 加载
# 值为
# 将其
# 转换为
# 金融
# ai
# 编码
# go语言
# golang
# go
# json
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
win11如何卸载Windows更新补丁 Win11解决更新导致系统不稳定的问题【修复】
京东京造J1和网易云音乐氧气真无线有什么不同_国产电商蓝牙耳机音质对比
电脑屏幕颜色不舒服怎么办_Windows夜间模式与色彩校准教程【护眼技巧】
怎么在mac上运行html代码_mac运行html代码方法【指南】
CSS Flexbox如何实现多行排列_flex-wrap wrap自动换行显示
taptap防沉迷怎么解除 taptap解除健康系统限制说明【2025最新】
拷贝漫画电脑版官网入口 拷贝漫画(PC版)在线直达
深入理解Promise链:如何在catch后中断then的执行
AI抖音网页版免费视频入口 AI抖音网页端最新视频实时观看
抖音网页版企业服务中心登录入口_抖音网页版企业登录平台
优酷会员付费后没到账怎么办_优酷会员充值异常及解决方法
极兔快递快件信息查询系统 极兔快递官网运单号追踪
win11如何加载ICC颜色配置文件 Win11校色文件安装与显示器色彩管理【指南】
Go与Ruby之间实现AES加密互通:CFB模式下的密钥长度匹配策略
魅族17怎样用浏览器译外语网页_iPhone魅族17浏览器译外语网页【即时翻译】
Python:递归比较文件夹内容并找出特定类型文件的差异
Win11怎么查看电脑配置_Win11硬件配置检测工具使用
蛙漫漫画免费阅读入口_蛙漫官方正版无广告纯净版
Lar*el递归关系中排除子孙节点的策略
顺丰快递查单号物流信息 顺丰快递小程序查询入口
4399免费游戏网址入口 4399小游戏免费入口点开即玩
c++中的std::forward_list和std::list有什么不同_c++ forward_list与list区别分析
高德地图沿途添加点失败如何解决 高德多点规划方法
中兴Axon42Ultra怎样在文件App筛图_iPhone中兴Axon42Ultra文件App筛图【图片筛选】
QQ邮箱官方网站登录入口_QQ邮箱网页版在线使用
必由学网页版入口 必由学官方平台直接访问
HTML转PPT成品工具有哪些?HTML网页转PPT成品工具大全
格力空气能E5故障代码是什么情况_格力空气能E5代码解析与应对措施
Fabric模组开发:自定义物品与物品组的现代管理方法
12306选座怎么选到特殊座位_12306特殊座位选择注意事项
c++如何实现单例设计模式_c++线程安全的单例模式写法
Go语言中Map值调用指针接收器方法的限制与应对
CSS实现侧边栏导航项全宽圆角悬停背景效果
凉拌黄瓜怎么拌更入味 凉拌黄瓜简单家常做法
必由学官方平台入口 必由学在线课堂登录地址
Lar*el Form Request中唯一性验证在更新操作中的正确实现
内存检查:在VS Code中调试C++时的内存视图
C++如何操作大型数据集_使用C++流式处理(Streaming)技术避免一次性加载大文件
斑马英语APP如何开启夜间护眼阅读_斑马英语APP夜间模式与低蓝光设置教程
怎么在html里运行vbs脚本_html中运行vbs脚本方法【教程】
Lar*el 递归关系中排除指定分支的教程
如何在J*a中实现统一对象行为接口_项目大型化时的接口规范化
高德地图公交到站提醒失败如何解决 高德提醒权限设置
AO3官方可用镜像 Archive of Our Own网页版最新入口
想当下一个《2077》?《心之眼》Steam评价升至"多半好评"
12306选座怎么选到商务座_12306商务座选择与配置说明
PHP 枚举:根据字符串获取枚举案例的策略与实现
写好的html代码怎么运行出来_运行写好的html代码方法【教程】
特斯拉自动驾驶房车计划曝光 原型车将于2027年亮相
J*a如何使用AtomicInteger控制计数_J*a无锁计数器性能分析


2025-11-29
浏览次数:次
返回列表
// 遍历 map,检查数字类型
if m, ok := data.(map[string]interface{}); ok {
for k, v := range m {
if num, isNumber := v.(json.Number); isNumber {
fmt.Printf("字段 '%s' 是 json.Number 类型,值为: %s\n", k, num)
// 可以根据需要转换为 int64 或 float64
if i, err := num.Int64(); err == nil {
fmt.Printf(" -> 转换为 int64: %d\n", i)
}
if f, err := num.Float64(); err == nil {
fmt.Printf(" -> 转换为 float64: %f\n", f)
}
} else {
fmt.Printf("字段 '%s' 是其他类型,值为: %v\n", k, v)
}
}
}
// 再次编码回JSON字符串
result, err := json.Marshal(data)
if err != nil {
log.Fatalf("编码失败: %v", err)
}
// 打印再次编码后的JSON,数字字段将保持原始格式
fmt.Printf("再次编码后的JSON: %s\n", result)
}