serdeã®æ©è½ã§æ§ã ãªå½¢æ ã®JSONãåæåã¨ãã¦æ±ã
JSONã¯REST APIå¼ã³åºãããã¼ã¿ä¿åãå¤è¨èªã¨ã®é£æºãªã©ã«æ°å¤ã使ç¨ããã¦ããã ä¸æ¹ã§ãJSONã¯è¨èªã§ãµãã¼ãããã表ç¾ãæ´æ°ã¨æµ®åå°æ°ç¹æ°ã»æååã»é åã»ãªãã¸ã§ã¯ãã»ããã¦nullç¨åº¦ãããªãããã以ä¸ã«è¤éãªè¡¨ç¾ã¯ãããã®åºæ¬æ©è½ãçµã¿åããã¦è¡¨ç¾ãããã¨ã«ãªãã æ©è½ã®çµã¿åããæ¹ã«ã¯è¤æ°ã®æ¹æ³ããããç¹ã«è¤æ°ã®åã®æ§é ä½ãã¯ã©ã¹ãæ··å¨ããæã®è¡¨ç¾å½¢å¼ã¯è¤æ°ããã
Rustã§ã¯ã表ç¾ããããã¼ã¿åãæ¢ç¥ã§ããã°ãè¤æ°ã®åã®ãã¡ã©ããã§ãããã¨ã表ç¾ããããã«åæåã使ããã ããã¦ãRustã®ã·ãªã¢ã©ã¤ã¶ã»ãã·ãªã¢ã©ã¤ã¶ã®ã©ã¤ãã©ãªã§ããserdeãç¨ãã¦ãåæåã¨JSONã®ç¸äºå¤æããããã¨ãã§ããã
åæä½ã®4種ã®è¡¨ç¾
serdeã§åãæ±ããåæä½ã®è¡¨ç¾å½¢å¼ã¯4種é¡ãã*1ã ããããexternally taggedãinternally taggedãadjacently taggedãuntaggedã®4種é¡ãæå®å¯è½ã§ããã
以ä¸ã®èª¬æã§ã¯ãåæä½ã®æ§æåï¼variantï¼ã®4å½¢å¼ãããããunitåæ§æåãnewtypeåæ§æåãtupleåæ§æåãstructåæ§æåã¨å¼ã¶ã ããããã¯Rustã®ã³ã¼ãã§ä»¥ä¸ã®ããã«æ¸ãããã
enum Varints { Unit, Newtype(i64), Tuple(i64, i64), Struct{x: i64, y: i64}, }
以ä¸ã®ãµã³ãã«ã³ã¼ãã®å®å ¨ãªã½ã¼ã¹ã³ã¼ãã¯ä»¥ä¸ã®ãªãã¸ããªã«ããã
GitHub - IgaguriMK/serde-enum-samples
Externally tagged (ããã©ã«ã)
externally taggedã¯ãå¤ã®å¤å´ã«ãªãã¸ã§ã¯ãã®ãã¼ã¨ãã¦ã¿ã°ãä»ããå½¢å¼ã§ããã ããã¯ã2018å¹´12ææç¹ã§serdeã®ããã©ã«ãæå®ã§ãããä½ã®æå®ãè¡ããªãã£ãå ´åãã®å½¢å¼ã使ç¨ãããã
ãã®å½¢å¼ã¯æ§æåãèªãã§ããå 容ãèªãããã¨ãJSON以å¤ã«ãå¤ãã®ãã©ã¼ãããã§å©ç¨å¯è½ãªãã¨ããã¹ã¦ã®ãã¿ã¼ã³ã®æ§æåããã¾ã表ç¾ã§ãããã¨ãªã©ãããããã©ã«ãã®å½¢å¼ã¨ãã¦é¸æããã¦ããããã ã ï¼tupleæ§æåã¯å 容ãé åã¨ãã¦è¡¨ç¾ãããï¼
{ "Variant": {"field1": "value1", "field2": "value2"}}
åæåã®å®£è¨æã«å½¢å¼ã®æå®ãè¡ããªããã¨ã§ãã®å½¢å¼ã使ç¨ãããã¨ãã§ããã
#[derive(Debug, Serialize, Deserialize)] enum Member { Permanent { id: u64, name: String, nickname: Option<String>, }, SingleChannel { channel_id: u64, name: String, nickname: Option<String>, }, }
å®éã®åä½ä¾ã¯ä»¥ä¸ã®éãã
Rustã§ã®å¤
[Permanent { id: 1, name: "Jebediah Kerman", nickname: Some("Jeb") }, Permanent { id: 2, name: "Bob Kerman", nickname: None }, SingleChannel { channel_id: 8, name: "Kamler Kerman", nickname: None }]
[{"Permanent":{"id":1,"name":"Jebediah Kerman","nickname":"Jeb"}},{"Permanent":{"id":2,"name":"Bob Kerman","nickname":null}},{"SingleChannel":{"channel_id":8,"name":"Kamler Kerman","nickname":null}}]
Internally tagged
internally taggedã¯ããªãã¸ã§ã¯ãã®ä¸ã«ã¿ã°ã¨ãªããã¼ã¨å¤ã®ãã¢ãå«ã¾ããå½¢å¼ã§ããã
{ "field1": "value1", "tag": "Variant", "field2": "value2"}
ãã®å½¢å¼ã使ç¨ããã«ã¯ãåæåã®å®£è¨ã«ã¢ããªãã¥ã¼ã㧠#[serde(tag="tag")]
ã¨ããããã«ã¿ã°ã¨ãªããã£ã¼ã«ããæå®ããã
ãã®å½¢å¼ã¯tupleæ§æåãå«ã¾ããå ´åã«ã¯å©ç¨ã§ãããunitæ§æåã¯ã¿ã°ã ããå«ã¾ãããªãã¸ã§ã¯ãã«ãªãã
newtypeæ§æåã¯ãä¸èº«ãæ§é ä½ã®å ´åã®ã¿ããã®æ§é ä½ãæ¸ãããstructæ§æåã¨åæ§ã«å©ç¨ã§ããã
internally taggedå½¢å¼ã使ãéã«ã¯ãåæåã«å¯¾å¿ããæ§æåããªãã¿ã°ããã¹ã¦otheræå®ããæ§æåã«ãã·ãªã¢ã©ã¤ãºããããã¨ãã§ããï¼å¾è¿°ï¼ã
#[derive(Debug, Serialize, Deserialize)] #[serde(tag = "type")] enum Member { Permanent { id: u64, name: String, nickname: Option<String>, }, SingleChannel { channel_id: u64, name: String, nickname: Option<String>, }, }
Rustã§ã®å¤
[Permanent { id: 1, name: "Jebediah Kerman", nickname: Some("Jeb") }, Permanent { id: 2, name: "Bob Kerman", nickname: None }, SingleChannel { channel_id: 8, name: "Kamler Kerman", nickname: None }]
[{"type":"Permanent","id":1,"name":"Jebediah Kerman","nickname":"Jeb"},{"type":"Permanent","id":2,"name":"Bob Kerman","nickname":null},{"type":"SingleChannel","channel_id":8,"name":"Kamler Kerman","nickname":null}]
Adjacently tagged
adjacently taggedå½¢å¼ã¯ããªãã¸ã§ã¯ãã®ä¸ã«ã¿ã°ã¨ãªããã¼ã¨å¤ã®ãã¢ã¨ãå 容ã¨ãªããã¼ã¨å¤ã®ãã¢ãå«ã¾ããå½¢å¼ã§ããã ã¿ã°ã¨å 容ãé£æ¥ãã¦ããï¼adjacentlyï¼ãããã®ååãã¤ãã¦ããã
{ "t": "Variant", "c": {"field1": "value1", "field2": "value2"}}
ãã®å½¢å¼ã使ç¨ããã«ã¯ãåæåã®å®£è¨ã«ã¢ããªãã¥ã¼ã㧠#[serde(tag="t", content="c")]
ã¨ããããã«ã¿ã°ã¨ãªããã£ã¼ã«ãã¨å
容ã¨ãªããã£ã¼ã«ããæå®ããã
ãã®å½¢å¼ã¯ãã¹ã¦ã®ç¨®é¡ã®æ§æåã«ä½¿ç¨ã§ããã
adjacently taggedå½¢å¼ã«ããã¦ããåæåã«å¯¾å¿ããæ§æåããªãã¿ã°ããã¹ã¦otheræå®ããæ§æåã«ãã·ãªã¢ã©ã¤ãºããããã¨ãã§ããï¼å¾è¿°ï¼ã
#[derive(Debug, Serialize, Deserialize)] #[serde(tag = "t", content = "c")] enum Member { Permanent { id: u64, name: String, nickname: Option<String>, }, SingleChannel { channel_id: u64, name: String, nickname: Option<String>, }, }
Rustã§ã®å¤
[Permanent { id: 1, name: "Jebediah Kerman", nickname: Some("Jeb") }, Permanent { id: 2, name: "Bob Kerman", nickname: None }, SingleChannel { channel_id: 8, name: "Kamler Kerman", nickname: None }]
[{"t":"Permanent","c":{"id":1,"name":"Jebediah Kerman","nickname":"Jeb"}},{"t":"Permanent","c":{"id":2,"name":"Bob Kerman","nickname":null}},{"t":"SingleChannel","c":{"channel_id":8,"name":"Kamler Kerman","nickname":null}}]
Untagged
untaggedå½¢å¼ã¯ãJSONã«ã¿ã°ãå«ã¾ãªãå½¢å¼ã§ããã
{"field1": "value1", "field2": "value2"}
ãã®å½¢å¼ã使ç¨ããã«ã¯ãã¢ããªãã¥ã¼ã㧠#[serde(untagged)]
ã¨æå®ããã
ãã®å½¢å¼ã¯ãã¹ã¦ã®ç¨®é¡ã®æ§æåã«å¯¾ãã¦ä½¿ç¨ã§ããããåæåã®æ§é 次第ã§ã¯ä¸æã«ã·ãªã¢ã©ã¤ãºã»ãã·ãªã¢ã©ã¤ãºãã§ããªãå ´åãåå¨ããï¼å¾è¿°ï¼ã
#[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] enum Member { Permanent { id: u64, name: String, nickname: Option<String>, }, SingleChannel { channel_id: u64, name: String, nickname: Option<String>, }, }
Rustã§ã®å¤
[Permanent { id: 1, name: "Jebediah Kerman", nickname: Some("Jeb") }, Permanent { id: 2, name: "Bob Kerman", nickname: None }, SingleChannel { channel_id: 8, name: "Kamler Kerman", nickname: None }]
[{"id":1,"name":"Jebediah Kerman","nickname":"Jeb"},{"id":2,"name":"Bob Kerman","nickname":null},{"channel_id":8,"name":"Kamler Kerman","nickname":null}]
Untaggedå½¢å¼ã®æ³¨æç¹
untaggedå½¢å¼ã§ã¯ãã·ãªã¢ã©ã¤ãºæã¯åã«ä¸èº«ãæ¸ãåºãããã·ãªã¢ã©ã¤ãºæã«ã¯åæåã®æ§æåãåããé çªã«è©¦ããã¨ã§ãã·ãªã¢ã©ã¤ãºããã ãããã£ã¦ãuntaggedå½¢å¼ã使ãéã«ã¯ãã¾ããã·ãªã¢ã©ã¤ãºãããããã«æ§æåã®é çªã工夫ããå¿ è¦ãããã
ä¾ãã°ãæ´æ°ã»æµ®åå°æ°ç¹æ°ã»æååã®ã©ããã«ãªãåæåãå®ç¾©ããå ´åã以ä¸ã®ããã«ãªãã ï¼ã³ã¼ãä¾ï¼
use failure::Error; use serde_derive::{Deserialize, Serialize}; pub fn run() -> Result<(), Error> { println!("\n======== Untagged enum with multiple types ========\n"); let string = r#"[1.0, 42, "foo"]"#; let values: Vec<Values> = serde_json::from_str(&string)?; println!("String: {}", string); println!("Decoded: {:?}", values); Ok(()) } #[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] enum Values { Int(i64), Float(f64), Str(String), }
ä¸è¨ã®ã³ã¼ããå®è¡ããã¨ã以ä¸ã®ããã«æ£ããæ´æ°ã»æµ®åå°æ°ç¹æ°ã»æååã«ãã·ãªã¢ã©ã¤ãºãããã
======== Untagged enum with multiple types ======== String: [1.0, 42, "foo"] Decoded: [Float(1.0), Int(42), Str("foo")]
ãããã以ä¸ã®ããã«æµ®åå°æ°ç¹æ°ã®æ¹ãåã«ããã¨ãæ´æ°ã¯å¿ ãæµ®åå°æ°ç¹æ°ã¨ãã¦ããã·ãªã¢ã©ã¤ãºã§ãããããæ´æ°ãæµ®åå°æ°ç¹æ°ã«ãã·ãªã¢ã©ã¤ãºããã¦ãã¾ãã ï¼ã³ã¼ãä¾ï¼
#[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] enum Values { Float(f64), Int(i64), Str(String), }
======== Untagged enum with multiple types ======== String: [1.0, 42, "foo"] Decoded: [Float(1.0), Float(42.0), Str("foo")]
serdeã®ä»ã®æ©è½ã¨ã®çµã¿åãã
other
internally taggedå½¢å¼ãadjacently taggedå½¢å¼ã®ã©ã¡ããã使ç¨ãã¦ããæãunitæ§æåãåæåã®æå¾ã«ã㦠#[serde(other)]
ã¢ããªãã¥ã¼ããã¤ãããã¨ã§ãã¿ã°ãã©ã®æ§æåã«ã該å½ããªãæã®å¤ã«ãããã¨ãã§ããã
ï¼ã³ã¼ãä¾ï¼
#[derive(Debug, Serialize, Deserialize)] #[serde(tag = "education")] enum Education { #[serde(rename = "high school")] HighSchool { name: String }, #[serde(rename = "college")] College { name: String, speciality: String }, #[serde(rename = "bachelor")] Bachelor { name: String, speciality: String }, #[serde(rename = "master")] Master { name: String, speciality: String }, #[serde(rename = "doctor")] Doctor { name: String, speciality: String }, #[serde(other)] Other, }
[ {"education": "high school", "name": "Tokyo metropolitan Hibiya High School"}, {"education": "college", "name": "Kyouritsu Women's Junior College", "speciality": "english literature"}, {"education": "bachelor", "name": "Meiji University", "speciality": "laws"}, {"education": "master", "name": "Tokyo Institute of Technology", "speciality": "engineering"}, {"education": "doctor", "name": "The University of Tokyo", "speciality": "science"}, {"education": "baka", "name": "ãã«ç°å¤§å¦"} ]
[HighSchool { name: "Tokyo metropolitan Hibiya High School" }, College { name: "Kyouritsu Women\'s Junior College", speciality: "english literature" }, Bachelor { name: "Meiji University", speciality: "laws" }, Master { name: "Tokyo Institute of Technology", speciality: "engineering" }, Doctor { name: "The University of Tokyo", speciality: "science" }, Other]
tagãnullã§ãã£ãå ´åãotheræå®ããã£ã¦ããã·ãªã¢ã©ã¤ãºã§ã¨ã©ã¼ãçºçããã ï¼ã³ã¼ãä¾ï¼
å ±éé¨ãå¥ã®æ§é ä½ã«ãããã ã
serdeã§ã¯æ§é ä½ã®ãã£ã¼ã«ããæ§é ä½ã®ã¨ãã« #[serde(flatten)]
ã¢ããªãã¥ã¼ããæå®ãããã¨ã§ãå
å´ã®æ§é ä½ãå¤å´ã®æ§é ä½ã«å±éãããã¨ãã§ããã
ããã¯structæ§æåã®ãã£ã¼ã«ãã«ã使ç¨ã§ããã®ã§ããã¾ã使ç¨ãããã¨ã§å
±éé¨åãå¥ã®æ§é ä½ã¨ãã¦æ±ããã¨ãã§ããã
å
±éé¨åãããªãå ´åã«ã¯ãnewtypeæ§æåã使ç¨ãããã¨ãã§ããã
ããã¯å§è²ãç¨ããã³ã¼ãã¨ã®è¦ªåæ§ãé«ãã
use failure::Error; use serde_derive::{Deserialize, Serialize}; pub fn run() -> Result<(), Error> { println!("\n======== Extract fields to structs ========\n"); let string = r#"[ {"op": "Add", "type": "Miscellaneous", "name": "clean up room"}, {"op": "Add", "type": "Technical", "name": "fix Wi-Fi"}, {"op": "Take", "type": "Technical"}, {"op": "Take", "type": "Miscellaneous"} ]"#; let operations: Vec<Operation> = serde_json::from_str(&string)?; println!("String: {}", string); println!("Decoded: {:?}", operations); Ok(()) } #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "op")] enum Operation { Add { #[serde(flatten)] task_type: TaskType, #[serde(flatten)] task: Task, }, Take(TaskType), } #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "type")] enum TaskType { Technical, Miscellaneous, } #[derive(Debug, Serialize, Deserialize)] struct Task { name: String, }
ãããã«
serdeã¯Rustã®æ±ç¨ã·ãªã¢ã©ã¤ã¶ã»ãã·ãªã¢ã©ã¤ã¶ãã¬ã¼ã ã¯ã¼ã¯ã¨ãã¦ãRustã®åã¨æ±ç¨ã®ãã¼ã¿æ§é ã®å¤æé¨åã¨ãæ±ç¨ã®ãã¼ã¿æ§é ã¨åãã©ã¼ãããã®å¤æé¨åããã¾ãåé¢ããããã«è¨è¨ããã¦ããã serdeã®æ©è½ããã¾ãæ´»ç¨ãããã¨ã§ãè¤æ°ã®ãã©ã¼ãããã¨ã®äºææ§ãä¿ã¡ã¤ã¤ãæ´çãããRustã®ã³ã¼ããå®ç¾ã§ãããããããªãã å ¬å¼ããã¥ã¡ã³ãã«ã¯ããå¤ãã®æ©è½ã®è§£èª¬ãä¾ãè¼ã£ã¦ãããããç®ãéãã¦ããã¨ããã ããã