如何使用Serde解析一个可能反序列化失败的字段而不导致整个反序列化失败?

Ric*_*ast 5 error-handling rust deserialization serde

我正在反序列化一些作为请求传入的 JSON 对象。输入正文是嵌套的,但某些字段有时会因各种原因而格式错误。在那种情况下我仍然想要该物体的其余部分。这并不都必须通过 serde 来完成;但现在发生的情况是,如果单个子字段被搞乱,整个请求就会被丢弃。我想以某种方式仍然反序列化该结果并将该字段标记为错误。如何才能做到这一点?

例如,数据模式可能如下所示:

struct BigNested {
    a: Vec<A>,
    b: B, // definition omitted
}

struct A {
    keep_this: Foo,
    trouble: SometimesBad,
}
Run Code Online (Sandbox Code Playgroud)

trouble这是一个经常出现混乱的领域。我很乐意(例如)变成troubleaResult<SometimesBad, Whatever>并从那里处理它,但我不知道如何让 serde 让我这样做。

edw*_*rdw 3

某些字段有时格式错误

您没有说传入的 JSON 格式有多么错误。假设它仍然是有效的 JSON,您可以使用Serde 的结构flatten和自定义反序列化来完成此操作:

  • 自定义反序列化的方式对于有效的 JSON 输入永远不会失败,尽管如果输入具有意外格式,它可能不会返回预期类型的​​值。

  • 但这些意想不到的领域仍然需要去往某个地方。Serde 的结构flatten在这里可以派上用场来捕获它们,因为任何JSON 片段都可以反序列化为HashMap<String, Value>.

//# serde = { version = "1.0.103", features = ["derive"] }
//# serde_json = "1.0.44"
use serde::{Deserialize, Deserializer, de::DeserializeOwned};
use serde_json::Value;
use std::collections::HashMap;

#[derive(Deserialize, Debug)]
struct A {
    keep_this: Foo,
    trouble: SometimesBad,
}

#[derive(Deserialize, Debug)]
struct Foo {
    foo: i32,
}

#[derive(Deserialize, Debug)]
struct SometimesBad {
    inner: TryParse<Bar>,

    #[serde(flatten)]
    blackhole: HashMap<String, Value>,
}

#[derive(Deserialize, Debug)]
struct Bar {
    bar: String,
}

#[derive(Debug)]
enum TryParse<T> {
    Parsed(T),
    Unparsed(Value),
    NotPresent
}

impl<'de, T: DeserializeOwned> Deserialize<'de> for TryParse<T> {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        match Option::<Value>::deserialize(deserializer)? {
            None => Ok(TryParse::NotPresent),
            Some(value) => match T::deserialize(&value) {
                Ok(t) => Ok(TryParse::Parsed(t)),
                Err(_) => Ok(TryParse::Unparsed(value)),
            },
        }
    }
}

fn main() {
    let valid = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": "one"}}}"#;
    println!("{:#?}", serde_json::from_str::<A>(valid));

    let extra_field = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": "one"}, "extra": 2019}}"#;
    println!("{:#?}", serde_json::from_str::<A>(extra_field));

    let wrong_type = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": 1}}}"#;
    println!("{:#?}", serde_json::from_str::<A>(wrong_type));

    let missing_field = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "baz": "one"}}}"#;
    println!("{:#?}", serde_json::from_str::<A>(missing_field));

    let missing_inner = r#"{ "keep_this": { "foo": 1 }, "trouble": { "whatever": { "bar": "one"}}}"#;
    println!("{:#?}", serde_json::from_str::<A>(missing_inner));
}
Run Code Online (Sandbox Code Playgroud)

(功劳不全是我的。Serde的第 1583 期基本上包含了所有内容。)