如何使用Serde进行反序列化时转换字段? [英] How to transform fields during deserialization using Serde?
问题描述
我使用Serde将具有十六进制值 0x400
的XML文件反序列化为一个字符串,我需要将它转换为值 1024
作为 u32
。
我是否需要实现 Visitor
trait,这样我就可以将0x分开,然后从基本16解码400到基本10?如果是这样,我该怎么做,以便10个基本整数的反序列化保持不变?
deserialize_with
属性
最简单的解决方案是使用 Serde字段属性 deserialize_with
为您的字段设置自定义序列化功能。然后,您可以获取原始字符串并将其转换为适当的:
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
使用serde :: {Deserialize,Deserializer};
使用serde :: de :: Error;
$ b $ [b] [b]
struct EtheriumTransaction {
#[serde(deserialize_with =from_hex)]
account:u64,// hex
amount:u64,//十进制
}
fn from_hex<'de,D>(解串器:D) - >结果< u64,D ::错误>
其中
D:反序列化器< de>,
{
let s:& str =反序列化::反序列化(反序列化器)?
//比这个
更好的十六进制解码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(Could not derserialize);
assert_eq!(transaction.amount,100);
assert_eq!(transaction.account,0xDEAD_BEEF);
}
playground 从这里开始,将它推广到自己的类型以允许重用它是一小步: 请注意,使用任何其他现有的Serde实现来解码。在这里,我们解码为一个字符串片段( 此方法允许您添加或删除字段,因为内部反序列化类型可以根据需要进行任何操作。 另请参阅: I'm using Serde to deserialize an XML file which has the hex value Do I need to implement the The easiest solution is to use the Serde field attribute From here, it's a tiny step to promoting it to your own type to allow reusing it: Note how this can use any other existing Serde implementation to decode. Here, we decode to a string slice ( This method allows you to also add or remove fields as the "inner" deserialized type can do basically whatever it wants. See also: 这篇关于如何使用Serde进行反序列化时转换字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
$ b 实现
serde :: Deserialize $ c
$ b pre
$ b
#[derive(Debug,Deserialize)]
struct EtheriumTransaction {
account:Account,// hex
amount:u64,// decimal
$ b $#[derive(Debug,PartialEq)]
struct Account(u64);
impl<'de>反序列化<去>用于帐户{
fn反序列化< D>(反序列化器:D) - >结果< Self,D :: Error>
其中
D:反序列化器< de>,
{
let s:& str =反序列化::反序列化(反序列化器)?
//比这个
更好的十六进制解码u64 :: from_str_radix(& s [2 ..],16)
.map(Account)
.map_err(D: :Error :: custom)
}
}
let s:& str = Deserialize :: deserialize(deserializer)?
)。
0x400
as a string and I need to convert it to the value 1024
as a u32
.Visitor
trait so that I separate 0x and then decode 400 from base 16 to base 10? If so, how do I do that so that deserialization for base 10 integers remains intact?The
deserialize_with
attributedeserialize_with
to set a custom serialization function for your field. You then can get the raw string and 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);
}
Implement
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)
}
}
let s: &str = Deserialize::deserialize(deserializer)?
).