2015-10-29 14 views
9

JSON to Rust yapısını rustc_serialize kullanarak serileştirmeye çalışıyorum. Sorun, belirli JSON'ların bazı isteğe bağlı alanlara sahip olmasıdır, yani mevcut olabilir veya olmayabilir. İlk boş alanla karşılaşıldığında, kod çözücü, mevcut olsalar bile, sonraki alanları dikkate almamaya ve kurtarmaya benziyor. Bunu aşmanın bir yolu var mı? İşte JSC'deki isteğe bağlı alanları, Rustc serileştirmesiyle açılamıyor

kodudur:

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

ve burada çıkış var: Üçüncü çalışma beklenmeyen bir sonuç ürettiğini

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

dikkat edin. Kod çözücü some_field_0 bulmak için başarısız olduğunda, some_field_1 mevcut olsa bile, sonraki tüm simgelerinde başarısız olur.

+1

Paslı serileştirmede bir hataya benziyor. [Github] (https://github.com/rust-lang-nursery/rustc-serialize) – aochagavia

cevap

6

Decodable uygulamanızın bir sorunu var. Otomatik olarak oluşturulan uygulama kullanma çalışır: üretilen uygulanmasını kullanma

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

Eğer eğer yapılacak doğru şey olduğunu. yapamazsın, burada sağ uygulama görebilirsiniz:

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

önemli değişiklik try! kullanılmasıdır. Kod çözme başarısız olabilir. ok kullanarak, başarısız bir kod çözmenin, None'un başarılı bir kod çözme de olsa, aslında başarısı olduğunu söylüyordunuz.

+0

ile ilgili bir sorunu bildirmeyi düşünün, oluşturulan uygulamanın işe yaramayacağını düşünmek için uyuşturulmuş olmalıyım: D .. Gönderdiğiniz manuel uygulama ile devam edin, denemeyin! İstediğim şey bu değildi - 'Yok' olarak koymam gerekiyordu ve bir sonraki alanı incelemeye devam ettim. Bu oldukça genişletilmiş sürümüne henüz bakmadım, ancak varsayılan olarak çalışmasını sağlamak için ne yaptığını görmek için. – ustulation

+0

Yukarıdaki yorumumu yanıtlama girişimi olarak: "Seçenek " için bir uzmanlık olması gerekir. Böylece, kod çözme işlemi için bir "T" kodunun ayrıştırılması ve daha fazla bir şey yapmaması gerekir. "Seçenek " hangi daha gevşek olacak ve alan bulunamadı, ancak kurtarmak ve EOF (ama başka bir hata için başka türlü aynı davranış) ulaşmak değilse 'Yok' dönmek. Orada mıyım? – ustulation