2017-07-12 5 views
1

私は2つの形式がありますJSONありますキー名に基づいて列挙型にデシリアライズする方法はありますか?

"Example:" { "field": 42, "A": 76 } 
"Example:" { "field": 42, "B": 110 } 

私はこのような構造体にそれをデシリアライズしたい:

enum AnEnum { 
    A(i32), 
    B(i32), 
} 

私はどのように知りません

struct Example { 
    field: i32, 
    an_enum: AnEnum, 
} 

Exampleのカスタムデシリアライザを作成せずに実行します。

"Example:" { "field": 42, "an_enum": {"A": 76} } 

をか、YAMLで:

これは動作します

Example: 
    field: 42 
    an_enum: 
     A: 76 

an_enumは余分と書くのは面倒です。構造体に最初のフォームをどのように逆シリアル化できますか?または、代わりに、私が望む構文を正常に逆シリアル化する構造体を宣言する方法はありますか?

答えて

2

Serdeにはenum representationsの可能な番号がありますが、希望の構造はその中にはありません。

その代わりに、私は、カスタム直列化復元を使用したい:

extern crate serde; 
extern crate serde_json; 
#[macro_use] 
extern crate serde_derive; 

use serde::{Deserialize, Deserializer}; 
use serde::de::Error; 

#[derive(Debug)] 
struct Example { 
    field: i32, 
    an_enum: AnEnum, 
} 

#[derive(Debug)] 
enum AnEnum { 
    A(i32), 
    B(i32), 
} 

impl<'de> Deserialize<'de> for Example { 
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 
    where 
     D: Deserializer<'de>, 
    { 
     #[derive(Debug, Deserialize)] 
     struct Mapping { 
      field: i32, 
      #[serde(rename = "A")] 
      a: Option<i32>, 
      #[serde(rename = "B")] 
      b: Option<i32>, 
     } 

     let Mapping { field, a, b } = Mapping::deserialize(deserializer)?; 

     match (a, b) { 
      (Some(_), Some(_)) => 
       Err(D::Error::custom("multiple variants specified")), 
      (Some(a), None) => 
       Ok(Example { field, an_enum: AnEnum::A(a) }), 
      (None, Some(b)) => 
       Ok(Example { field, an_enum: AnEnum::B(b) }), 
      (None, None) => 
       Err(D::Error::custom("no variants specified")), 
     } 
    } 
} 

fn main() { 
    let a = r#"{ "field": 42, "A": 76 }"#; 
    let b = r#"{ "field": 42, "B": 110 }"#; 

    let a: Result<Example, _> = serde_json::from_str(a); 
    let b: Result<Example, _> = serde_json::from_str(b); 

    println!("{:?}", a); 
    println!("{:?}", b); 
} 
+0

はい、私はカスタム直列化復元でそれを行う方法を知っています。私はいくつかの亜種を持っているとき、このコードは面倒になり、私の現在の仕事で少なくとも2回起こります。私が望むのは、 'an_enum'フィールドに何らかのタグが付いている(またはシリアライゼーションでは省略されている)ということです。 –

+0

私は 'r#...'表記に慣れていません。あなたはそれを説明できますか? –

+1

@StevePowell https://stackoverflow.com/questions/26611664/the-operator-r-in-rust –

関連する問題