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

标签 rust hex serde

我正在使用Serde对具有十六进制值0x400作为字符串的XML文件进行反序列化,并且需要将其转换为1024的值u32

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

最佳答案

deserialize_with属性

最简单的解决方案是使用Serde field attribute deserialize_with为您的字段设置自定义序列化功能。然后,您可以获取原始字符串和convert it as appropriate:

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

playground

请注意,这如何使用任何其他现有的Serde实现进行解码。在这里,我们解码为字符串切片(let s: &str = Deserialize::deserialize(deserializer)?)。您还可以创建直接映射到原始数据的中间结构,在其上派生Deserialize,然后在Deserialize的实现中将其反序列化。

实现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)
    }
}

playground

此方法还允许您添加或删除字段,因为“内部”反序列化类型基本上可以完成所需的操作。

也可以看看:
  • How to transform fields during serialization using Serde?
  • 关于rust - 如何使用Serde在反序列化期间转换字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63259359/

    相关文章:

    javascript - 在 Javascript 中为给定的 HEX 值创建线性渐变

    c++ - C++ hex2bin 缺少标点符号

    rust - 为什么没有为明确实现的类型实现特征?

    rust - 为什么一个特征没有为一个明确实现的类型实现?

    rust - 如何使用toml-rs和serde_derive反序列化两种不同的结构和文件格式?

    rust - "cd"执行一系列命令时没有效果

    pointers - 为什么 `offset_from` 使用的指针必须从指向同一对象的指针派生?

    java - 如何在java中将类的对象转换为十六进制数组

    testing - 如何在不要求参数函数可变的情况下测试元函数?

    rust - 文件结构不被视为实现读取?