rust 有没有办法让serde_json正确/不正确地处理NaN、Inf和-Inf(IEEE 754 Specials)?

2q5ifsrm  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(71)

官方的JSON规范不支持IEEE 754,而是有自己的null(不是“null”)或正常数字的约定。
在许多语言和用例中,人们忽略了这一点,并偏离规范以支持IEEE 754浮点数。

>>> json.dumps(dict(a = np.inf, b = -np.inf, c = np.nan), allow_nan=True)
'{"a": Infinity, "b": -Infinity, "c": NaN}'

字符串
在这种情况下,allow_nan默认为True。
同样,在C#中,我们可以将数字处理设置为AllowNamedFloatingPointLiterals以获得相同的行为
https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonnumberhandling?view=net-8.0
那么,我们怎样才能让rust/serde_json做同样的事情--serde_json中是否有一个标志可以做到这一点,如果没有,添加此功能的最简单方法是什么?(我的意思是以用户的身份实现此功能,而不是通过更新serde_json源代码或分叉它或任何东西)。

编辑:根据一些评论,假设我们同意JSON是错误的,是否有一种格式可以代替JSON,完全支持浮点数。

或者,如何实现一个JSON有效的替代方案,如使用“Infinity”作为字符串。据我所知,这将影响所有其他序列化,所以如果你序列化的结构BSON,CBOR,msgpack等。

重新编辑

所以我自己的研究提出了几种可能性:

  • JSON 5显然扩展了JSON,同时向后兼容。
  • serde untaged enum可能有一些神奇的技巧,但我不知道这是不是真的。看起来serde可以依次尝试一系列格式,直到其中一个成功-如果serde_json尝试序列化一个Special Float(严格来说,这是JSON规范所要求的),有没有办法让serde_json FAIL?
f45qwnt8

f45qwnt81#

  • serde_json* 能处理这些特殊的浮点数吗?不能,因为它严格遵守JSON规范。但是,JSON5支持这些时髦的浮点数,serde_json5忠实地实现了JSON 5:
use std::collections::HashMap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let map = HashMap::<_, _>::from_iter([
        ("a", 1.0),
        ("b", f64::NAN),
        ("c", f64::INFINITY),
        ("d", f64::NEG_INFINITY),
    ]);

    let j = serde_json5::to_string(&map)?;
    let o = serde_json5::from_str::<HashMap<String, f64>>(&j)?;

    println!("JSON5: {}", j);
    println!("HashMap: {:?}", o);

    Ok(())
}

字符串
输出量:

JSON5: {"a":1,"b":NaN,"d":-Infinity,"c":Infinity}
HashMap: {"a": 1.0, "d": -inf, "c": inf, "b": NaN}

1bqhqjot

1bqhqjot2#

它是unsupported
维护者的答案并不完全清楚,因为我不认为serde_json暴露了你可以添加回退的解析器钩子,我认为通常的解决方案(deserialize_with)对此已经太迟了。
所以你可能想要求精确度,但乍一看,你似乎必须维护一个自定义的serde_json分支/分支来支持非标准扩展。

相关问题