当前位置:首页 > 文章列表 > Golang > Go教程 > Go jsontext Token 怎样在读取 token 数值(输入边界)

Go jsontext Token 怎样在读取 token 数值(输入边界)

来源:17golang原创 2026-10-25 05:16:12 0浏览 收藏

在 Go 1.27 的 encoding/json/jsontext 中,Token 表示 JSON 词法层的一个 token。读取数字时,关键不是直接调用 Int() 或 Uint(),而是先确认 Kind() == jsontext.KindNumber,再根据业务需要选择整数或浮点读取方法。

官方文档:https://pkg.go.dev/encoding/json/jsontext

安全读取 token 数值可以记成四步:先判数字类型,再选 accessor;用 errors.Is 识别语法或范围错误;最后注意 ReadToken 返回值可能依赖 Decoder 缓冲区。Int、Uint 出错时仍可能返回一个合理值,不能只看数值不看 error。
  • KindNumber 只说明 token 是 JSON 数字,不保证它适合目标 Go 类型。
  • Int 和 Uint 可能发生向零截断,超范围时会返回饱和值并带错误。
  • 从 Decoder.ReadToken 得到的原始 token,在下一次 Decoder 调用后不应继续依赖;需要保存时先 Clone。

先用 Kind 确认 token 真的是数字

Token 不只表示数字,还可以表示 null、布尔值、字符串以及对象和数组的起止分隔符。数字 accessor 对错误的 token 类型会 panic,因此输入来自外部 JSON 时,第一层判断应放在读取方法之前。

下面的辅助函数只把 JSON 数字交给 Int,其它 token 直接返回带上下文的错误。注释中的每个判断都对应一个输入边界,业务层可以再把错误映射成自己的字段错误。

package main

import (
    "fmt"

    "encoding/json/jsontext"
)

func readInt(tok jsontext.Token) (int64, error) {
    // 先挡住字符串、布尔值和结构分隔符,避免 Int 对非数字 token 触发 panic。
    if tok.Kind() != jsontext.KindNumber {
        return 0, fmt.Errorf("expected JSON number, got %s", tok.Kind())
    }

    // Int 会解析带符号的整数语义,返回值是否可用必须和 error 一起判断。
    n, err := tok.Int()
    if err != nil {
        return 0, fmt.Errorf("read integer %q: %w", tok.String(), err)
    }
    return n, nil
}

这里的 KindNumber 是必要条件,但不是完整的业务校验。例如 token 文本可以是带小数或指数的 JSON 数字,是否允许这类输入要交给 Int 的错误结果和业务规则共同决定。

Go jsontext Token 从 KindNumber 分流到 Int Uint Float 的静态关系说明图
图1:Token 类型与数值 accessor 的静态关系说明图,重点查看数字 token 与不同读取方法的边界;这不是运行截图。

Int、Uint 和 Float 的选择不要混用

有符号计数、可能出现负值的偏移量适合 Int();业务字段明确不允许负数且范围对应 uint64 时才使用 Uint()。普通 JSON 数字需要小数或指数语义时使用 Float()。Float32() 只适合调用方已经知道这个 token 按 32 位精度生成的场景,不能为了节省一个变量宽度就默认使用。

func readCount(tok jsontext.Token) (uint64, error) {
    // 无符号计数不接受非数字 token,负数和不符合无符号整数语义的文本交给 Uint 报错。
    if tok.Kind() != jsontext.KindNumber {
        return 0, fmt.Errorf("count must be a JSON number, got %s", tok.Kind())
    }
    n, err := tok.Uint()
    if err != nil {
        return 0, fmt.Errorf("invalid count %q: %w", tok.String(), err)
    }
    return n, nil
}

func readRatio(tok jsontext.Token) (float64, error) {
    // 比例允许小数,因此不能用 Int;Float 按 64 位精度读取 JSON 数字。
    if tok.Kind() != jsontext.KindNumber {
        return 0, fmt.Errorf("ratio must be a JSON number, got %s", tok.Kind())
    }
    n, err := tok.Float()
    if err != nil {
        return 0, fmt.Errorf("invalid ratio %q: %w", tok.String(), err)
    }
    return n, nil
}

不要把字符串形式的 "12" 当成数字 token 来调用这些方法。Token.String() 对字符串返回解码后的字符串值,对数字返回原始 JSON 表示;它适合放进错误信息或日志,但不能代替 Kind() 做类型判断。

语法错误、范围错误和截断要分开处理

Int() 与 Uint() 会用与 strconv.ErrSyntax、strconv.ErrRange 匹配的错误说明问题。范围错误时仍可能返回一个合理值,超出目标整数表示范围时还会饱和到最近的可表示值,所以生产代码应先处理 error,再决定是否把结果交给业务层。

import (
    "errors"
    "fmt"
    "strconv"

    "encoding/json/jsontext"
)

func classifyInt(tok jsontext.Token) (int64, error) {
    // 先确认调用前提,数值方法本身不会替调用方检查 Kind。
    if tok.Kind() != jsontext.KindNumber {
        return 0, fmt.Errorf("not a number: %s", tok.Kind())
    }
    n, err := tok.Int()
    if err == nil {
        return n, nil
    }
    // ErrSyntax 表示输入形态不符合当前整数读取语义,例如负号/小数规则不匹配。
    if errors.Is(err, strconv.ErrSyntax) {
        return 0, fmt.Errorf("integer syntax is invalid for %q: %w", tok.String(), err)
    }
    // ErrRange 表示不能无损放进 int64;即使 n 有值,也不能当成精确结果。
    if errors.Is(err, strconv.ErrRange) {
        return 0, fmt.Errorf("integer is out of int64 range: %w", err)
    }
    return 0, fmt.Errorf("read integer: %w", err)
}

文档明确说明整数读取会忽略小数部分并向零截断,因此 12.9 这类输入不能在业务上默认视为“合法整数”。如果字段必须是整数,应在 token 层保留原始表示并增加格式约束,不能把截断后的结果悄悄写回数据库或计数器。

Go jsontext Token 数字读取的语法范围截断和 Decoder 缓冲区边界说明图
图2:数值 token 的语法、范围、截断与生命周期边界说明图;图中关系是静态解释,不是运行结果。

ReadToken 返回值需要注意 Clone

如果 token 是通过 Decoder.ReadToken 得到的,它的原始 JSON 文本可能由 Decoder 的内部缓冲区支持。下一次调用 Decoder 的方法后,这个 token 不应再被当成独立值使用。需要把 token 放进队列、缓存、异步任务或错误记录时,先调用 Clone()。

func keepNumber(dec *jsontext.Decoder) (jsontext.Token, error) {
    tok, err := dec.ReadToken()
    if err != nil {
        return jsontext.Token{}, err
    }
    if tok.Kind() != jsontext.KindNumber {
        return jsontext.Token{}, fmt.Errorf("expected number, got %s", tok.Kind())
    }

    // 跨过下一次 Decoder 调用仍要使用,因此复制脱离 Decoder 缓冲区的 token。
    return tok.Clone(), nil
}

相反,jsontext.Int(42)、jsontext.Uint(42)、jsontext.Float(0.5) 等构造出来的 token 本身已经独立保存,不需要为了生命周期再次 Clone。这一区别只影响 token 的存活时间,不会改变数字解析的类型或范围规则。

常见问题

调用 Token.Int 之前一定要判断 Kind 吗?

只要 token 来源不受你完全控制,就应该判断。Int、Uint 会对非数字 token panic,提前判断能把输入问题转成普通 error。

Uint 能读取负数吗?

不能把负数当作无符号整数接受。应让 Uint 返回错误,并按 strconv.ErrSyntax 或 strconv.ErrRange 分类处理。

为什么 Int 返回了数值还要看 error?

因为语法不匹配或超出 int64 范围时,文档允许返回一个合理值或饱和值。只有 error 为 nil 时,才适合把该数值当作无损读取结果。

Token.Clone 会把数字转换成别的类型吗?

不会。Clone 只把依赖 Decoder 缓冲区的原始 token 复制成独立 token,不负责类型转换、范围检查或业务校验。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go go/doc/comment.Parser 怎样解析文档注释Go go/doc/comment.Parser 怎样解析文档注释
上一篇
Go go/doc/comment.Parser 怎样解析文档注释
Go utf8.RuneLen 怎样判断 rune 占用几个字节
下一篇
Go utf8.RuneLen 怎样判断 rune 占用几个字节
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    677次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    696次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    738次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    707次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    543次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码