2017-10-15 14 views
4

Serdeを使用して、16進値0x400を文字列として持つXMLファイルを逆シリアル化して、1024u32という値に変換する必要があります。Serdeを使用して逆シリアル化中にフィールドを変換する方法は?

Visitor特性を実装して、0xを分離して、ベース16からベース10に400をデコードする必要がありますか?もしそうなら、どのようにしてベース10の整数の非直列化がそのまま残るようにするのですか?

答えて

5

最も簡単な解決策は、Serde field attributedeserialize_withを使用して、フィールドのカスタムシリアル化機能を設定することです。それはそれを再利用できるようにするために、独自のタイプにそれを促進する小さなステップだが、ここから

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

その後、生の文字列と convert it as appropriateを得ることができます

も参照してください。

+0

ありがとう@Shepmaster。これはまさに私が探しているものです。唯一の問題は、私がこのパニックを得るときの文字列への参照ですmsg:無効な型:文字列 "0x400"、借用文字列が必要です。 – phodina

+0

@phodinaどちらの例も正常に実行されているので、明らかに何かを変更しました。私は心の読者ではないので、その違いは何か分かりません。 XMLデコーダが文字列スライスを提供できない場合、 'let s:String = ...'を試すことができます。 – Shepmaster

+0

私は両方の例をプレイグラウンドと自分のPCで試しましたが、どちらもうまくいきます。この問題は、基礎となる形式をjsonからxmlに変更すると発生します。ここにコードはありますか?(遊び場にはserrate_xml_rsがありません) raw = r# " 0xDEADBEEF"# トランザクション:EtheriumTransaction = serde_xml_rs :: deserialize(raw.as_bytes())。unwrap(); – phodina

関連する問題