我试图使用rustc_serialize将JSON反序列化为Rust struct .问题是某些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存在.

推荐答案

您的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表示解码失败实际上是success,尽管成功解码了None.

Rust相关问答推荐

移植带有可变borrow 的C代码-卸载期间错误(nappgui示例)

如何从使用mockall模拟的方法中返回self?

新创建的变量的绑定生存期

如何将像烫手山芋一样不透明的值从一个Enum构造函数移动到下一个构造函数?

除了调用`waker.wake()`之外,我如何才能确保future 将再次被轮询?

是否可以使用Rust宏来构建元组的项?

在rust sqlx中使用ilike和push bind

为什么TcpListener的文件描述符和生成的TcpStream不同?

对reqwest提供的这种嵌套JSON struct 进行反序列化

什么是`&;[][..]`铁 rust 里的刻薄?

tokio::sync::broadcast::Receiver 不是克隆

为什么切片时需要参考?

闭包返回类型的生命周期规范

(let b = MyBox(5 as *const u8); &b; ) 和 (let b = &MyBox(5 as *const u8); ) 之间有什么区别

Some(v) 和 Some(&v) 有什么区别?

为什么 &i32 可以与 Rust 中的 &&i32 进行比较?

在 Rust 中返回对枚举变体的引用是个好主意吗?

在空表达式语句中移动的值

Cargo:如何将整个目录或文件包含在功能标志中?

火箭整流罩、tokio-scheduler 和 cron 的生命周期问题