Как преобразовать поля при десериализации с помощью Serde?

Я использую Serde для десериализации XML-файла, который имеет шестнадцатеричное значение 0x400 в виде строки, и мне нужно преобразовать его в значение 1024 как u32,

Нужно ли реализовывать Visitor черта, чтобы я отделял 0x, а затем декодировал 400 из базы 16 в базу 10? Если да, то как мне сделать так, чтобы десериализация для целых 10-ти чисел осталась нетронутой?

1 ответ

deserialize_with атрибут

Самое простое решение - использовать атрибут поля Serde.deserialize_with установить пользовательскую функцию сериализации для вашего поля. Затем вы можете получить необработанную строку и преобразовать ее соответствующим образом:

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

use serde::{Deserialize, Deserializer};
use serde::de::Error;

#[derive(Debug, Deserialize)]
struct EtheriumTransaction {
    #[serde(deserialize_with = "from_hex")]
    account: u64, // hex
    amount: u64,  // decimal
}

fn from_hex<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
    D: Deserializer<'de>,
{
    let s: &str = Deserialize::deserialize(deserializer)?;
    // do better hex decoding than this
    u64::from_str_radix(&s[2..], 16).map_err(D::Error::custom)
}

fn main() {
    let raw = r#"{"account": "0xDEADBEEF", "amount": 100}"#;
    let transaction: EtheriumTransaction =
        serde_json::from_str(raw).expect("Couldn't derserialize");
    assert_eq!(transaction.amount, 100);
    assert_eq!(transaction.account, 0xDEAD_BEEF);
}

детская площадка

Воплощать в жизнь serde::Deserialize

Отсюда, это маленький шаг в продвижении его к вашему типу, чтобы позволить его повторное использование:

#[derive(Debug, Deserialize)]
struct EtheriumTransaction {
    account: Account, // hex
    amount: u64,      // decimal
}

#[derive(Debug, PartialEq)]
struct Account(u64);

impl<'de> Deserialize<'de> for Account {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s: &str = Deserialize::deserialize(deserializer)?;
        // do better hex decoding than this
        u64::from_str_radix(&s[2..], 16)
            .map(Account)
            .map_err(D::Error::custom)
    }
}

детская площадка

Обратите внимание, как это может использовать любую другую существующую реализацию Serde для декодирования. Здесь мы декодируем на фрагмент строки (let s: &str = Deserialize::deserialize(deserializer)?).

Этот метод позволяет также добавлять или удалять поля, так как "внутренний" десериализованный тип может делать в основном все, что захочет.

Смотрите также:

Другие вопросы по тегам