【问题标题】:Unable to tackle optional fields in JSON with Rustc-serialize无法使用 Rustc-serialize 处理 JSON 中的可选字段
【发布时间】:2015-10-29 10:40:35
【问题描述】:

我正在尝试使用 rustc_serialize 将 JSON 反序列化为 Rust 结构。问题是某些 JSON 有一些可选字段,即可能存在也可能不存在。遇到第一个不存在的字段的那一刻,解码器似乎退出并且不考虑后续字段,即使它们存在。有没有办法克服这个问题?

代码如下:

extern crate rustc_serialize;

#[derive(Debug)]
struct B {
    some_field_0: Option<u64>,
    some_field_1: Option<String>,
}

impl rustc_serialize::Decodable for B {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
        Ok(B {
            some_field_0: d.read_struct_field("some_field_0", 0, |d| rustc_serialize::Decodable::decode(d)).ok(),
            some_field_1: d.read_struct_field("some_field_1", 0, |d| rustc_serialize::Decodable::decode(d)).ok(),
        })
    }
}

fn main() {
    {
        println!("--------------------------------\n1st run - all field present\n--------------------------------");
        let json_str = "{\"some_field_0\": 1234, \"some_field_1\": \"There\"}".to_string();
        let obj_b: B = rustc_serialize::json::decode(&json_str).unwrap();

        println!("\nJSON: {}\nDecoded: {:?}", json_str, obj_b);
    }

    {
        println!("\n\n--------------------------------\n2nd run - \"some_field_1\" absent\n---------------------------------");
        let json_str = "{\"some_field_0\": 1234}".to_string();
        let obj_b: B = rustc_serialize::json::decode(&json_str).unwrap();

        println!("\nJSON: {}\nDecoded: {:?}", json_str, obj_b);
    }

    {
        println!("\n\n--------------------------------\n3rd run - \"some_field_0\" absent\n---------------------------------");
        let json_str = "{\"some_field_1\": \"There\"}".to_string();
        let obj_b: B = rustc_serialize::json::decode(&json_str).unwrap();

        println!("\nJSON: {}\nDecoded: {:?}", json_str, obj_b);
    }
}

这是输出:

--------------------------------
1st run - all field present
--------------------------------

JSON: {"some_field_0": 1234, "some_field_1": "There"}
Decoded: B { some_field_0: Some(1234), some_field_1: Some("There") }


--------------------------------
2nd run - "some_field_1" absent
---------------------------------

JSON: {"some_field_0": 1234}
Decoded: B { some_field_0: Some(1234), some_field_1: None }


--------------------------------
3rd run - "some_field_0" absent
---------------------------------

JSON: {"some_field_1": "There"}
Decoded: B { some_field_0: None, some_field_1: None }

请注意,第三次运行会产生意想不到的结果。当解码器无法找到some_field_0 时,它会在所有后续令牌上失败,即使存在some_field_1

【问题讨论】:

  • 似乎是 rustc-serialize 中的一个错误。考虑在github 上提交问题

标签: json rust json-deserialization


【解决方案1】:

您的 Decodable 实现有问题。使用自动生成的实现作品:

#[derive(Debug, RustcDecodable)]
struct B {
    some_field_1: Option<String>,
    some_field_0: Option<u64>,
}
JSON: {"some_field_1": "There"}
Decoded: B { some_field_1: Some("There"), some_field_0: None }

使用生成的实现是正确的做法如果可以的话。如果你不能,这里是正确的实现:

impl rustc_serialize::Decodable for B {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
        Ok(B {
            some_field_0: try!(d.read_struct_field("some_field_0", 0, |d| rustc_serialize::Decodable::decode(d))),
            some_field_1: try!(d.read_struct_field("some_field_1", 0, |d| rustc_serialize::Decodable::decode(d))),
        })
    }
}

重要的变化是try!的使用。解码可能会失败。通过使用ok,您是说解码失败实际上是成功,尽管None 的成功解码。

【讨论】:

  • 我一定是被迷住了,以为生成的实现不起作用:D .. 但是如果我们确实采用您发布的手动实现,try! 不会导致提早返回吗?这不是我想要的——我需要把它写成None 并继续检查下一个字段。我还没有看过那个相当扩展的版本,但要看看 default 是如何使它工作的。
  • 就像试图回答我上面的评论一样:Option&lt;T&gt; 必须有一个专门化,以便它可以区分解码为 TOption&lt;T&gt;,如果没有找到该字段但没有退出并达到EOF(但其他任何错误的行为相同),它将更加宽松并返回None。我在附近吗?
猜你喜欢
  • 2019-07-30
  • 2023-02-16
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多