2017-06-01 53 views
5

Özel işlevlerle bir chrono::NaiveDate serileştirmek ve serileştirmek istiyorum, ancak Serde kitabı bu işlevi kapsamaz ve kod belgeleri de yardımcı olmaz.İsteğe bağlı bir alanı Serde kullanarak özel işlevlerle nasıl deserialize edebilirim?

#[macro_use] 
extern crate serde_derive; 
extern crate serde; 
extern crate serde_json; 
extern crate chrono; 

use chrono::NaiveDate; 


mod date_serde { 
    use chrono::NaiveDate; 
    use serde::{self, Deserialize, Serializer, Deserializer}; 

    pub fn serialize<S>(date: &Option<NaiveDate>, s: S) -> Result<S::Ok, S::Error> 
    where S: Serializer { 
     if let Some(ref d) = *date { 
      return s.serialize_str(&d.format("%Y-%m-%d").to_string()) 
     } 
     s.serialize_none() 
    } 

    pub fn deserialize<'de, D>(deserializer: D) 
     -> Result<Option<NaiveDate>, D::Error> 
     where D: Deserializer<'de> { 
     let s: Option<String> = Option::deserialize(deserializer)?; 
     if let Some(s) = s { 
      return Ok(Some(NaiveDate::parse_from_str(&s, "%Y-%m-%d").map_err(serde::de::Error::custom)?)) 
     } 

     Ok(None) 
    } 
} 

#[derive(Debug, Serialize, Deserialize)] 
struct Test { 
    pub i: u64, 
    #[serde(with = "date_serde")] 
    pub date: Option<NaiveDate>, 
} 

fn main() { 
    let mut test: Test = serde_json::from_str(r#"{"i": 3, "date": "2015-02-03"}"#).unwrap(); 
    assert_eq!(test.i, 3); 
    assert_eq!(test.date, Some(NaiveDate::from_ymd(2015, 02, 03))); 
    test = serde_json::from_str(r#"{"i": 5}"#).unwrap(); 
    assert_eq!(test.i, 5); 
    assert_eq!(test.date, None); 
} 

Ben Chrono yüzden kendim uygulamak istiyorum ben serde öğrenmeye çalışıyorum ama serde desteği, çünkü Option<chrono::NaiveDate> kolayca serde tarafından seriden çıkarılabilir biliyorum. tip burada Option ait

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ErrorImpl { code: Message("missing field `date`"), line: 1, column: 8 }', /checkout/src/libcore/result.rs:859 
note: Run with `RUST_BACKTRACE=1` for a backtrace. 

cevap

2

bir alan alan olmayabilir deserializer söylemez: Bu kodu çalıştırdığınızda bir hata var. Bunun yerine, boş veya boş içerikli bir alan içerdiğini gösterir (Serde cinsinden none). Örneğin, serde_json'da, Option<String>, "ya null veya string" (null | string, TypeScript/Flow gösterimi) öğesine eşdeğerdir. Aşağıda bu kod çalışıyor:

let test: Test = serde_json::from_str(r#"{"i": 5, "date": null}"#).unwrap(); 
assert_eq!(test.i, 5); 
assert_eq!(test.date, None); 

Neyse ki, seri kaldırma işlemi daha hoşgörülü hale gelebilir sadece serde(default) özniteliği (Option::default verimi None) ekleyerek:

#[derive(Debug, Serialize, Deserialize)] 
struct Test { 
    pub i: u64, 

    #[serde(default)] 
    #[serde(with = "date_serde")] 
    pub date: Option<NaiveDate>, 
} 

Playground

Ayrıca bkz How to deserialize a JSON file which contains null values using Serde? (yinelenen değil, ancak benzer ve uygun kullanım durumları içerir)

+1

Neden basit pub date: Seçenek '' date' alanı mevcut olduğunda seri hale getirir mi? –

+0

İlk paragrafta açıklanmıştır. Anlamadığınız şey hakkında daha spesifik olabilir misiniz? –

+1

affedersiniz, bir yazım hatası: ... "date" alanı ** mevcut değilken bir seriyi tamamlar. –