2015-10-29 6 views
9

rustc_serializeを使用してJSON to Rust構造を逆シリアル化しようとしています。問題は、特定のJSONにいくつかのオプションのフィールドがあることです。つまり、存在する場合もありません。最初の不在フィールドに遭遇した瞬間に、デコーダは脱出し、後続のフィールドが存在していても考慮しません。これを克服する方法はありますか?ここでRustc-serializeで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); 
    } 
} 

、ここでは出力です:3回目は、予期しない結果を生成すること

-------------------------------- 
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が存在しても)。

+1

rustc-serializeにバグがあります。 [github](https://github.com/rust-lang-nursery/rustc-serialize)の問題を提出することを検討してください – aochagavia

答えて

6

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のデコードに成功したと言われました。

+0

生成された実装がうまくいかないと思うには薬を飲んでいなければなりません:あなたが手作業で実装しようとすると、試してみませんでした。それは私が望んでいたものではありません - 私はそれを 'None'とし、次のフィールドを検査し続ける必要がありました。私はかなりの拡張版をまだ見ていないが、それを動作させるためにどのようなデフォルト設定が行われているかを見ています。 – ustulation

+0

上記の私のコメントに答えようとしているように、 'Option 'の特化が必要です。これは、デコードするTとそれ以上の何もしない 'T 'を区別でき、' Option 'そのフィールドが見つからない場合には 'None'を返すが、EOFに到達することはできません(他のエラーに対しては同じ動作)。 私はそこに閉じ込めていますか? – ustulation

関連する問題