【问题标题】:How can I deserialize a type where all the fields are default values as a None instead?如何将所有字段都是默认值的类型反序列化为 None ?
【发布时间】:2019-03-07 18:02:32
【问题描述】:

我必须反序列化 JSON blob,在某些地方,整个对象的缺失被编码为具有相同结构的对象,但其所有字段都设置为默认值(空字符串和零)。

extern crate serde_json; // 1.0.27
#[macro_use] extern crate serde_derive; // 1.0.78
extern crate serde; // 1.0.78

#[derive(Debug, Deserialize)]
struct Test<T> {
    text: T,
    number: i32,
}

#[derive(Debug, Deserialize)]
struct Outer {
    test: Option<Test<String>>,
}

#[derive(Debug, Deserialize)]
enum Foo { Bar, Baz }
#[derive(Debug, Deserialize)]
struct Outer2 {
    test: Option<Test<Foo>>,
}

fn main() {
    println!("{:?}", serde_json::from_str::<Outer>(r#"{ "test": { "text": "abc", "number": 42 } }"#).unwrap());
    // good: Outer { test: Some(Test { text: "abc", number: 42 }) }

    println!("{:?}", serde_json::from_str::<Outer>(r#"{ "test": null }"#).unwrap());
    // good: Outer { test: None }

    println!("{:?}", serde_json::from_str::<Outer>(r#"{ "test": { "text": "", "number": 0 } }"#).unwrap());
    // bad: Outer { test: Some(Test { text: "", number: 0 }) }
    // should be: Outer { test: None }

    println!("{:?}", serde_json::from_str::<Outer2>(r#"{ "test": { "text": "Bar", "number": 42 } }"#).unwrap());
    // good: Outer2 { test: Some(Test { text: Bar, number: 42 }) }

    println!("{:?}", serde_json::from_str::<Outer2>(r#"{ "test": { "text": "", "number": 0 } }"#).unwrap());
    // bad: error
    // should be: Outer { test: None }
}

我会在反序列化后处理这个问题,但正如您所见,这种方法不适用于枚举值:没有变体与空字符串匹配,因此反序列化完全失败。

如何教这个 serde?​​p>

【问题讨论】:

    标签: json rust serde serde-json


    【解决方案1】:

    你可以看看an example of custom field deserializing

    特别是,您可能想要定义类似

    extern crate serde; // 1.0.78
    #[macro_use]
    extern crate serde_derive; // 1.0.78
    
    use serde::{Deserialize, Deserializer, de::Visitor};
    
    fn none_if_all_default<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
    where
        T: Deserialize<'de>,
        D: Deserializer<'de> + Clone,
    {
        struct AllDefault;
    
        impl<'de> Visitor<'de> for AllDefault {
            type Value = bool;
    
            // Implement the visitor functions here -
            // You can recurse over all values to check if they're
            // the empty string or 0, and return true
            //...
        }
    
        let all_default = deserializer.clone().deserialize_any(AllDefault)?;
    
        if all_default {
            Ok(None)
        } else {
            Ok(Some(T::deserialize(deserializer)?))
        }
    }
    

    然后做

    #[derive(Deserialize)]
    struct Outer2 {
        #[serde(deserialize_with = "none_if_all_default")]
        test: Option<Test<Foo>>,
    }
    

    【讨论】:

    • 请增强您的示例,以显示如何按照 OP 的要求将其用于枚举。我无法让自己的示例与枚举一起使用。由于not all trait items implemented, missing: `expecting`,这也无法编译。
    • 它无法编译,因为它并不意味着编译 - 这是一个框架答案,并且实现该特征是可以通过参考文档来完成的手动工作。重点是展示解决OP问题的高级想法。这适用于enum 字段,因为它适用于Option&lt;T&gt; 的任何字段。
    • deserialize_any consumes self。一旦它消失了,你如何打电话给T::deserialize?您的函数的返回类型不一致(Result::OkOption::Some)。这个答案不起作用。
    • 反序列化器can not be cloned。请注意,这就是为什么强烈建议您在回答之前创建一个可行的解决方案的原因。
    猜你喜欢
    • 2018-08-20
    • 2020-05-31
    • 1970-01-01
    • 2021-10-27
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多