如何使用serde_json将“ NaN”反序列化为“ nan”?

时间:2019-01-31 03:07:30

标签: json rust floating-point serde

我有如下数据类型:

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Matrix {
    #[serde(rename = "numColumns")]
    pub num_cols: usize,
    #[serde(rename = "numRows")]
    pub num_rows: usize,
    pub data: Vec<f64>,
}

我的JSON正文看起来像这样:

{
    "numRows": 2,
    "numColumns": 1,
    "data": [1.0, "NaN"]
}

这是Jackson(从我们使用的Java服务器)提供的序列化,并且是有效的JSON。不幸的是,如果我们致电serde_json::from_str(&blob),则会收到错误消息:

Error("invalid type: string "NaN", expected f64", [snip]

我知道浮点数周围有一些微妙之处,人们对应该采用的方式抱有很大的看法。我尊重。特别是Rust,我非常乐于助人,我喜欢。

但是,到最后,这些JSON Blob才是我要接收的,并且我需要"NaN"字符串以反序列化为某个f64值,其中is_nan()为true ,并将其序列化回字符串"NaN",因为该生态系统的其余部分都使用了Jackson,在那很好。

这可以通过合理的方式实现吗?

编辑:建议的链接问题讨论了如何覆盖派生的derializer,但并未解释如何专门对float进行反序列化。

1 个答案:

答案 0 :(得分:1)

实际上似乎在Vec(或Map等)中使用自定义解串器是Serde上的一个未解决问题,并且已经使用了一年多(截至撰写本文时):https://github.com/serde-rs/serde/issues/723 < / p>

我相信解决方案是为f64(这很好)以及使用f64作为子对象的所有东西(例如Vec<f64>,{{1 }}等。不幸的是,这些方法的实现看起来像不是

HashMap<K, f64>

拥有反序列化器后,您只能通过访问者与其进行交互。

长话短说,我最终使它工作了,但是似乎很多代码不是必需的。将其张贴在这里,希望(a)某人知道如何清除它,或(b)确实是应该这样做,并且此答案对某人有用。我花了整整一天的时间认真阅读文档并进行反复试验,所以这可能对其他人很有用。 deserialize<'de, D>(deserializer: D) -> Result<Vec<f64>, D::Error> where D: Deserializer<'de> { /* snip */ } 函数应与字段名称上方的适当(de)serialize_float(s)一起使用。

#[serde( (de)serialize_with="etc." )]