-
Rust: serde De/Serialize traits into JSON컴퓨터/Rust 2021. 7. 19. 16:55728x90반응형
할 것
A 버튼이 있고, B 버튼이 있을 때 이 두 버튼은 Base 란 trait를 implement 한다.
(자바로 보면 class A implements Base)
이 trait를 implement한 struct들을 Vector에 담아서 이 결과를 json으로 바꾸고 싶은데
하지만 기본적으로는 trait는 불가능하다. 5시간 정도 헤매었다.
erased_serde crate를 사용하면 편해진다.
예제 코드
공식 문서에 예제가 없어 카카오톡 챗봇 반응에서 버튼 JSON을 만들 때를 코딩했다.
설명
ButtonJSON이란 struct가 있다.
이 구조체는 벡터 형식으로 trait를 implement한 모든 구조체들의 모음이다.
Button이란 trait를 보면 new, set_label, set_msg 메소드를 구현하라고 지정했다. (체인 형식)
CallButton, ShareButton, MsgButton 구조체들은 serde에서 Serialize attribute를 derive했다.
맨 아래 kakao_json이란 test 함수를 보면
ButtonJSON.buttons에 CallButton과 ShareButton을 저장해서 json string으로 변환해서 출력했다.
use serde::Serialize; /***** Buttons *****/ #[allow(patterns_in_fns_without_body)] pub trait Button: Serialize { fn new(msg: Option<String>) -> Self; fn set_label(mut self, label: String) -> Self; fn set_msg(mut self, msg: String) -> Self; } #[derive(Serialize)] pub struct ButtonJSON { #[serde(skip_serializing_if = "Vec::is_empty")] buttons: Vec<Box<dyn erased_serde::Serialize>>, } impl ButtonJSON { fn new() -> Self { ButtonJSON { buttons: Vec::new(), } } } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct CallButton { label: String, action: String, phone_number: String, #[serde(skip_serializing_if = "Option::is_none")] message_text: Option<String>, } impl Button for CallButton { fn new(msg: Option<String>) -> Self { CallButton { label: "label".to_string(), action: "phone".to_string(), phone_number: "0".to_string(), message_text: msg, } } fn set_label(mut self, label: String) -> Self { self.label = label; self } fn set_msg(mut self, msg: String) -> Self { self.message_text = Some(msg); self } } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct MsgButton { label: String, action: String, #[serde(skip_serializing_if = "Option::is_none")] message_text: Option<String>, } impl Button for MsgButton { fn new(msg: Option<String>) -> Self { MsgButton { label: "label".to_string(), action: "message".to_string(), message_text: msg, } } fn set_label(mut self, label: String) -> Self { self.label = label; self } fn set_msg(mut self, msg: String) -> Self { self.message_text = Some(msg); self } } #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct ShareButton { label: String, action: String, #[serde(skip_serializing_if = "Option::is_none")] message_text: Option<String>, } impl Button for ShareButton { fn new(msg: Option<String>) -> Self { ShareButton { label: "label".to_string(), action: "share".to_string(), message_text: msg, } } fn set_label(mut self, label: String) -> Self { self.label = label; self } fn set_msg(mut self, msg: String) -> Self { self.message_text = Some(msg); self } } /***** Buttons *****/ #[cfg(test)] mod test { use super::*; #[test] fn kakao_json() { let mut result = ButtonJSON::new(); result.buttons.push(Box::new( CallButton::new(None) .set_label("CALL LABEL".to_string()) .set_msg("MESSAGE".to_string()), )); result.buttons.push(Box::new(ShareButton::new(None))); println!("{}", serde_json::to_string(&result).expect("Woah")); } }
결과
{ "buttons": [ { "label": "CALL LABEL", "action": "phone", "phoneNumber": "0", "messageText": "MESSAGE" }, { "label": "label", "action": "share" } ] }
참고
현재 진행 중인 프로젝트
728x90'컴퓨터 > Rust' 카테고리의 다른 글
Rust: String 한글 len() (UTF-8) (0) 2021.07.20 Rust: diesel db query 코드 정리 (0) 2021.07.18 Rust: HTML 파싱하기 (crawling) (0) 2021.07.15