JSON

2015-10-24 32 views
5

'daki bir alana dayalı koşullu olarak JSON kodunu çözme Bir API'dan JSON alıyorum ve yanıt 30 türden biri olabilir. Her türün benzersiz bir alan kümesi vardır, ancak tüm yanıtlar, hangi tür olduğunu bildiren bir alan type'a sahiptir.JSON

Benim yaklaşımım serde kullanmaktır. Her yanıt tipi için bir yapı oluşturur ve bunları dekode edebilirim. Bir kez aldım, yeni alınmış bir mesaj için hangi yapının kullanılması gerektiğini nasıl seçerim?

Şu anda type için yalnızca bir alanla başka bir TypeStruct yapı oluşturdum. JSON'u bir TypeStruct içine çözüyorum, ardından tip değeri temel alınarak alınan mesaj için uygun yapıyı seçin ve mesajı tekrar çözün.

Bu kod çözme çoğaltmasından kurtulmak istiyorum.

+0

Şu anki çözümün benim yapacağım şey. "Kod çözme çoğaltması" nı engellemek konusunda daha iyi veya daha verimli olacağını düşünüyorsunuz? – Shepmaster

+0

Python'dan geliyorum, bu yüzden düzgün yazılan dillerle kendinizi rahat hissetmiyorum. Ama eğer diyorsan, benim yaklaşımım iyi, onunla bağlı kalacağım. – eyeinthebrick

+0

Sadece benim düşüncem, ama bu optimizasyon hakkında endişe verici erken bir örnek gibi geliyor. Çalıştırmak ve yeterince hızlı olup olmadığını görmek için kodunuzu alın. Değilse, kodunuzu değiştirmeden önce profilinize ekleyin - belki de JSON kod çözme problemi bile değil. – llogiq

cevap

6

Mevcut enum serileştirme özelliğini kullanabilirsiniz. örnek json dize ile

#[derive(Debug, PartialEq, Eq, Deserialize)] 
enum MyType { 
    A {gar:()}, 
    B {test: i32}, 
    C {blub: String}, 
} 
  1. Başlangıç: Bir Value enum

    içine

    let json = r#"{"type": "B", "test": 42}"#; 
    
  2. Hafta onu ben şu enum Formatınızı serisini adım örnek bir adım vereceğiz

    let mut json: serde_json::Value = serde_json::from_str(json).unwrap(); 
    
  3. type alanından çıkma

    let type_ = { 
        let obj = json.as_object_mut().expect("object"); 
        let type_ = obj.remove("type").expect("`type` field"); 
        if let serde_json::Value::String(s) = type_ { 
         s 
        } else { 
         panic!("type field not a string"); 
        } 
    }; 
    
  4. "Uygun" enum json'u oluşturun. alanın adıdır enum varyantı ve alanın değeri olan tek bir alanla bir yapı

    let mut enum_obj = std::collections::BTreeMap::new(); 
    enum_obj.insert(type_, json); 
    let json = serde_json::Value::Object(enum_obj); 
    
  5. enum

    bir değer haline json açmak için oluşturulan json deserializer kullanın varyant değeridir
    let obj: MyType = serde_json::from_value(json).unwrap(); 
    
+1

Sorunun özetlendiği "iki kez kod çözme" çözümüyle karşılaştırıldığında, bunun verimliliği üzerindeki herhangi bir sayı veya gut hissi? – Shepmaster

+3

daha çok bir DRY çözümü. Bu şekilde, iki konumda herhangi bir türle işlem yapmanız gerekmez. Sadece enum ilan etmelisin. Olası tüm türleri veya hiçbir şeyle asla eşleşmemeli. Hızla bu, Soruda sunulan çözümden muhtemelen daha kötüdür (bir çok "String" alanı var ve struct/enum alanları yoksa, muhtemelen Sorudaki çözümden daha hızlıdır). Tam kodu görmeden bilmek zor. Daha hızlı olan genel çözümler, json dizgisinde alan sırasına ilişkin kesin bilgiye ve/veya serde –

+0

numaralı telefona hasebiyle ilgili kesin bilgiye ihtiyaç duyar. Teşekkürler, sizin önerdiğiniz gibi bir şey olabileceğinden şüpheleniyorum. Aynı tekniği pas serileştirerek kullanabilir miyim? – eyeinthebrick