2015-10-29 17 views
9

Tôi đang cố gắng hủy bỏ cấu trúc JSON thành Rust bằng cách sử dụng rustc_serialize. Vấn đề là một số JSON nhất định có một số trường tùy chọn, tức là, có thể có hoặc không có mặt. Thời điểm trường đầu tiên vắng mặt gặp phải, bộ giải mã dường như được bảo lãnh và không xem xét các trường tiếp theo, ngay cả khi chúng có mặt. Có cách nào để vượt qua điều này không?Không thể xử lý các trường tùy chọn trong JSON với mã hóa tuần tự

Đây là mã:

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); 
    } 
} 

và đây là kết quả:

-------------------------------- 
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 } 

ý rằng thời gian thứ ba tạo ra một kết quả bất ngờ. Khi bộ giải mã không tìm thấy some_field_0 nó không thành công trên tất cả các mã thông báo tiếp theo, mặc dù some_field_1 có mặt.

+1

Có vẻ như một lỗi trong tuần tự hóa. Xem xét việc gửi một vấn đề trên [github] (https://github.com/rust-lang-nursery/rustc-serialize) – aochagavia

Trả lời

6

Có vấn đề với việc triển khai Decodable của bạn. Sử dụng thực hiện tự động tạo ra hoạt động:

#[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 } 

Sử dụng thực hiện tạo là điều đúng đắn nên làm nếu bạn có thể. Nếu bạn không thể, đây là triển khai đúng:

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))), 
     }) 
    } 
} 

Thay đổi quan trọng là sử dụng try!. Giải mã có thể thất bại. Bằng cách sử dụng ok, bạn đã nói rằng giải mã không thành công thực sự là một thành công , mặc dù giải mã thành công None.

+0

tôi phải đã bị ma túy để nghĩ rằng việc thực hiện được tạo ra sẽ không hoạt động: D .. nhưng nếu chúng ta làm đi với thực hiện thủ công bạn đã đăng sẽ không 'cố gắng! 'gây ra một sự trở lại sớm? Đó không phải là những gì tôi muốn - tôi cần phải đặt nó là "Không" và tiếp tục kiểm tra lĩnh vực tiếp theo. Tôi đã không nhìn vào phiên bản khá mở rộng đó mặc dù để xem những gì mặc định không để làm cho nó hoạt động. – ustulation

+0

Cũng giống như một cố gắng trả lời bình luận của tôi ở trên: Phải có một chuyên môn cho 'Option ' để nó có thể phân biệt giữa giải mã thành 'T' mà nó sẽ giải cứu và không làm gì thêm và' Option 'cho mà nó sẽ khoan dung hơn và trả về 'None' nếu trường không được tìm thấy nhưng không được bảo lãnh và tiếp cận EOF (nhưng nếu không có hành vi tương tự đối với bất kỳ lỗi nào khác). Tôi có ở gần đó không? – ustulation

Các vấn đề liên quan