首页 > 后端开发 > Golang > 正文

Go中解析JSON时保留64位整数值的方法

花韻仙語
发布: 2025-10-16 11:30:13
原创
148人浏览过

Go中解析JSON时保留64位整数值的方法

go语言中处理json数据时,当使用`json.unmarshal`将包含大整数(如64位整数)的json解析到`map[string]interface{}`时,这些整数可能会被默认转换为`float64`,导致精度丢失。本文将详细介绍两种有效方法来避免这种问题:一是利用`json.decoder`的`usenumber()`方法将数字解析为`json.number`类型,再手动转换;二是定义明确的go结构体,直接将大整数类型指定为`uint64`或`int64`进行解码。

在Go语言的encoding/json包中,当使用json.Unmarshal将JSON数据解析到interface{}类型(例如map[string]interface{})时,它会将JSON中的数字字面量默认解析为Go的float64类型。对于不超出float64精度范围的整数而言,这通常不是问题。然而,当JSON中包含的整数值超过float64所能精确表示的最大整数(即2^53)时,就会发生精度丢失。例如,一个64位整数(如4418489049307132905)在转换为float64后,其低位信息可能会被截断或四舍五入。

以下是两种在Go中解析JSON时保留64位整数值的解决方案。

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

encoding/json包提供了一个Decoder类型,它比直接使用json.Unmarshal提供了更精细的控制。通过Decoder的UseNumber()方法,我们可以指示解码器将所有JSON数字解析为json.Number类型,而不是默认的float64。json.Number实际上是一个字符串类型,它保留了数字的原始字符串表示,从而避免了任何潜在的精度损失。之后,我们可以根据需要将其转换为int64或uint64。

示例代码

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "strconv"
)

func main() {
    body := []byte(`{"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}`)

    // 创建一个map来存储解析后的数据
    dat := make(map[string]interface{})

    // 创建一个新的JSON解码器
    d := json.NewDecoder(bytes.NewBuffer(body))

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

    // 解码JSON数据
    if err := d.Decode(&dat); err != nil {
        panic(err)
    }

    // 访问解析后的数据
    tags, ok := dat["tags"].([]interface{})
    if !ok {
        panic("tags not found or not an array")
    }

    // 遍历标签并处理ID
    for i, tag := range tags {
        tagMap, ok := tag.(map[string]interface{})
        if !ok {
            fmt.Printf("tag %d is not a map\n", i)
            continue
        }

        idNum, ok := tagMap["id"].(json.Number)
        if !ok {
            fmt.Printf("tag %d id is not a json.Number\n", i)
            continue
        }

        // 将json.Number转换为uint64
        // 根据实际数据范围选择ParseInt或ParseUint
        id64, err := strconv.ParseUint(string(idNum), 10, 64)
        if err != nil {
            fmt.Printf("Error parsing id %s: %v\n", idNum, err)
            continue
        }
        fmt.Printf("tag: %d id: %d (Type: %T)\n", i, id64, id64)
    }
}
登录后复制

工作原理

  1. json.NewDecoder(bytes.NewBuffer(body)):创建一个Decoder实例,从字节切片中读取JSON数据。
  2. d.UseNumber():这是关键步骤。它告诉解码器将JSON中的所有数字作为json.Number类型进行处理。json.Number本质上是一个string别名,存储了数字的原始文本表示。
  3. d.Decode(&dat):执行解码操作。
  4. tagMap["id"].(json.Number):在访问id字段时,需要将其断言为json.Number类型。
  5. strconv.ParseUint(string(idNum), 10, 64):将json.Number(其底层是字符串)转换为uint64类型。10表示十进制,64表示目标位宽。如果数字可能为负数,应使用strconv.ParseInt。

这种方法提供了最大的灵活性,但需要额外的类型断言和字符串转换步骤。

Find JSON Path Online
Find JSON Path Online

Easily find JSON paths within JSON objects using our intuitive Json Path Finder

Find JSON Path Online 30
查看详情 Find JSON Path Online

解决方案二:解码到自定义结构体

更Go惯用且通常更推荐的方法是定义一个与JSON结构相匹配的Go结构体(struct)。通过明确指定结构体字段的类型为uint64或int64,json.Unmarshal可以直接将JSON中的数字解析到这些字段,而无需经过float64的中间转换。

示例代码

package main

import (
    "encoding/json"
    "fmt"
)

// 定义与JSON结构对应的Go结构体
type Tag struct {
    ID uint64 `json:"id"` // 明确指定ID为uint64类型
}

type Data struct {
    Tags []Tag `json:"tags"` // 包含Tag结构体的切片
}

func main() {
    body := []byte(`{"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}`)

    var data Data
    // 直接将JSON数据解码到自定义结构体
    if err := json.Unmarshal(body, &data); err != nil {
        panic(err)
    }

    // 访问解析后的数据
    for i, tag := range data.Tags {
        fmt.Printf("tag: %d id: %d (Type: %T)\n", i, tag.ID, tag.ID)
    }
}
登录后复制

工作原理

  1. 定义结构体:创建Tag和Data结构体,它们的字段名称和类型与JSON数据中的键和值相匹配。
  2. 类型指定:将Tag结构体中的ID字段明确指定为uint64(或int64)。json:"id"是结构体标签,用于将JSON键id映射到Go结构体字段ID。
  3. 直接解码:使用json.Unmarshal(body, &data)将JSON数据直接解码到Data类型的变量中。

这种方法更具结构化,代码更简洁,类型安全,且易于维护。对于已知JSON结构的场景,这是首选方案。

注意事项

  • JavaScript的限制:如果您的应用程序涉及到JavaScript,需要注意JavaScript标准中没有64位整数类型,它只有IEEE 754双精度浮点数。这意味着,即使您在Go中正确处理了64位整数,当这些数据传递到JavaScript前端时,如果直接使用标准的JSON解析函数,仍然可能丢失精度。在JavaScript中处理大整数通常需要特殊的库(如BigInt)或将大整数作为字符串进行传输。
  • 选择方案
    • 当JSON结构未知或高度动态时,json.Decoder配合UseNumber()提供了更大的灵活性。
    • 当JSON结构已知且稳定时,解码到自定义结构体是更清晰、更类型安全且易于维护的选择。

总结

在Go语言中解析JSON数据时,为了避免64位整数值在默认解码过程中被转换为float64并导致精度丢失,我们有两种主要的策略。第一种是利用json.Decoder的UseNumber()方法将数字解析为json.Number字符串,然后手动转换为int64或uint64。第二种是定义与JSON结构相对应的Go结构体,并明确指定大整数字段的类型为int64或uint64。这两种方法都能有效解决精度问题,开发者应根据实际需求和JSON结构的复杂性选择最合适的方案。

以上就是Go中解析JSON时保留64位整数值的方法的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号