我使用Serde反序列化具有十六进制值0x400
作为字符串的XML文件,我需要将其转换为值1024
作为u32
。
我是否需要实现Visitor
特性,以便将0x分开,然后将400从基数16解码到基数10?如果是这样,我该怎么做才能使基数10整数的反序列化保持不变?
答案 0 :(得分:12)
deserialize_with
属性最简单的解决方案是使用Serde field attribute deserialize_with
为您的字段设置自定义序列化功能。然后,您可以获取原始字符串convert it as appropriate:
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)?
)。
此方法允许您添加或删除字段,因为“内部”反序列化类型基本上可以执行任何操作。
另见: