如何使用Serde在反序列化期间转换字段?

pho*_*ina 10 hex rust serde

我使用SERDE反序列化具有十六进制值的XML文件0x400作为一个字符串,我需要将其转换为数值1024u32.

我是否需要实现Visitor特性,以便将0x分离,然后将400从基数16解码到基数10?如果是这样,我该怎么做才能使基数10整数的反序列化保持不变?

She*_*ter 14

deserialize_with属性

最简单的解决方案是使用Serde字段属性 deserialize_with为您的字段设置自定义序列化功能.然后,您可以获取原始字符串并根据需要进行转换:

use serde::{de::Error, Deserialize, Deserializer}; // 1.0.94
use serde_json; // 1.0.40

#[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);
}
Run Code Online (Sandbox Code Playgroud)

操场

实行 let s: &str = Deserialize::deserialize(deserializer)?

从这里开始,将它推广到您自己的类型是一个很小的步骤,以允许重复使用它:

#[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)
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

请注意,这可以使用任何其他现有的Serde实现进行解码.在这里,我们解码为字符串slice(Deserialize).

此方法允许您添加或删除字段,因为"内部"反序列化类型基本上可以执行任何操作.

也可以看看: