programing

Serde를 사용하여 커스텀 함수를 사용하여 옵션 필드를 역직렬화하려면 어떻게 해야 합니까?

newnotes 2023. 3. 1. 11:28
반응형

Serde를 사용하여 커스텀 함수를 사용하여 옵션 필드를 역직렬화하려면 어떻게 해야 합니까?

serialize 및 serialize 해제chrono::NaiveDate커스텀 기능을 탑재하고 있습니다만, Serde Book에서는 이 기능에 대해 설명하고 있지 않습니다.또, 코드 문서도 도움이 되지 않습니다.

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

나는 그것을 알고 있습니다.Option<chrono::NaiveDate>Chrono가 Serde를 지원하고 있기 때문에 Serde에 의해 쉽게 역직렬화 될 수 있지만 Serde를 배우려고 하기 때문에 직접 구현하고 싶습니다.이 코드를 실행하면 다음 오류가 발생합니다.

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.

structure deserialization의 기본 동작은 필드가 시리얼화된 형식으로 존재하지 않을 때 각각의 기본값을 사용하여 필드를 할당하는 것입니다.이것은 구조체의 기본값으로 필드를 채우는 컨테이너 속성과는 다릅니다.

#[derive(Debug, PartialEq, Deserialize)]
pub struct Foo<'a> {
    x: Option<&'a str>,
}

let foo: Foo = serde_json::from_str("{}")?;
assert_eq!(foo, Foo { x: None });

그러나 다른 역직렬화 함수()#[serde(deserialize_with = "path")]를 사용하면 이 규칙이 변경됩니다.활자 필드Option여기서 필드가 존재하지 않을 수 있음을 디시리얼라이저에 알리지 않습니다.오히려 빈 내용 또는 늘 내용이 있을 수 있는 필드가 있음을 나타냅니다.none(Serde 용어로)serde_json예를 들어.Option<String>JavaScript는 다음과 같습니다.null또는string" (null | stringTypeScript / Flow 표기법).다음 코드는 지정된 정의 및 날짜 역직렬화기에서 올바르게 작동합니다.

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

운 좋게도, 탈직렬화 과정은 단지 추가되는 것만으로 더 관대해질 수 있습니다.serde(default)속성(Option::default수율None):

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

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

놀이터.

다음 항목도 참조하십시오.

언급URL : https://stackoverflow.com/questions/44301748/how-can-i-deserialize-an-optional-field-with-custom-functions-using-serde

반응형