Skip to content

Number Model

github-actions[bot] edited this page Aug 12, 2026 · 2 revisions

Number Model

JSON 数字的保真是 NextJson 的一个显式设计目标Number 不是裸 f64,而是 一个无损枚举。

Number 的定义

pub enum Number {
    I64(i64),      // 有符号 64 位
    U64(u64),      // 无符号 64 位(所有非负整数都用它)
    I128(i128),    // 超出 i64 范围的有符号 128 位
    U128(u128),    // 超出 u64 范围的无符号 128 位
    F64(f64),      // 64 位浮点(含 -0.0 与极端值)
}

三个关键设计决策

1. 非负整数统一存 U64(相等性修复)

Number::U64(v)所有非负整数的规范形式。原因是一个曾被测试抓到的相等性 撕裂:

let a: Number = 1i32.into();       // 旧实现 → Number::I64(1)
let b: Number = "1".parse()?;      // 解析 → Number::U64(1)
assert_eq!(a, b);                  // 旧实现:不等!(撕裂)

统一后 I64 只存负数,解析得到的正数与 From 构造的正数恒等。

2. 超出 u128 报错,不静默丢精度

  • 解析时手写整数词法 + 溢出检测:超 u128 的整数 → NumberOutOfRange 错误;
  • 因此 Value / 类型化解码都不会出现"大整数被悄悄转成浮点丢精度"。

3. 浮点整数补 ".0"

f64 整数(如 64.0)在 JSON 里序列化为 64.0 而非 64——保留浮点语义, 反序列化回 f64 时不会与整数类型混淆。

转换 API

n.as_i64()   // 尽力转 i64(浮点截断)
n.as_u64()   // 尽力转 u64
n.as_i128()  // 精确:仅当值是整数且范围内
n.as_u128()  // 精确:仅当值是整数且范围内
n.as_f64()   // 转 f64(可能丢精度,从不失败)
  • as_i128/as_u128F64 只在"有限且 % 1.0 == 0.0"时成功(no_stdf64::fract() 不可用,故用 % 1.0 判断整性);
  • 边界检查避免了 u64::MAX as f64 这类浮点舍入导致的越界误报/漏报。

宽度与格式

  • FormatEncoder 提供 write_number(&Number)(保留种类)与宽度方法 write_i8..i128 / write_u8..u128 / write_f32/f64
  • 默认宽度方法加宽到 i64/u64;二进制格式覆写为原生宽度写出(线上保留宽度, 如 postcard 的定宽整数);
  • 解码侧 Number 是自描述格式的中间载体,非自描述格式(postcard)通过宽度读取 直接还原。

诚实边界

  • 没有任意精度小数/大整数(u128 封顶)——这是文档明示的能力边界,超出 u128 的整数报错而不是用 f64 静默降级;
  • 这比 serde_json 默认的 arbitrary_precision(可选 feature)保守;serde 生态 的 bigdecimal/rust_decimal 走的是另一条路线。

相关页面

Clone this wiki locally