2017-10-15 34 views
4

我正在使用Serde反序列化一个XML文件,该文件的十六进制值为0x400作为字符串,我需要将其转换为值1024,作为u32如何使用Serde进行反序列化时转换字段?

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

回答

5

最简单的解决方案是使用Serde field attributedeserialize_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); 
} 

playground

从这里,这是一个很小的步骤,它推广到自己的类型,以便重新使用:

#[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

另请参阅:

+0

Thanks @Shepmaster。这正是我正在寻找的。唯一的问题是对字符串的引用,因为我得到这个恐慌消息:无效类型:字符串“0x400”,预计借用字符串。 – phodina

+0

@phodina我的两个例子都运行成功,显然你已经改变了一些东西。我不是一个心灵读者,所以我不知道那是什么区别。如果XML解码器不能提供字符串切片,您可以尝试'let s:String = ...'。 – Shepmaster

+0

我已经在操场上和我的电脑上试过了你的两个例子,他们都工作。当我将底层格式从json更改为xml时,问题就出现了。这里是代码(操作失误包装箱serde_xml_rs) let raw = r#“ 0xDEADBEEF”# let transaction:EtheriumTransaction = serde_xml_rs :: deserialize(raw.as_bytes())。unwrap(); – phodina

相关问题