Как преобразовать поля при десериализации с помощью 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)?
).
Этот метод позволяет также добавлять или удалять поля, так как "внутренний" десериализованный тип может делать в основном все, что захочет.
Смотрите также: