ABOUT ME

-

  • Rust: serde De/Serialize traits into JSON
    컴퓨터/Rust 2021. 7. 19. 16:55
    728x90
    반응형

    할 것

    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.buttonsCallButtonShareButton을 저장해서 json string으로 변환해서 출력했다.

    rust
    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")); } }

     

    결과

    json
    { "buttons": [ { "label": "CALL LABEL", "action": "phone", "phoneNumber": "0", "messageText": "MESSAGE" }, { "label": "label", "action": "share" } ] }

     

    참고

    현재 진행 중인 프로젝트

     

    Alfex4936/Rust-Backend

    Rocket web framework을 이용한 Rust 공부. Contribute to Alfex4936/Rust-Backend development by creating an account on GitHub.

    github.com

    728x90

    '컴퓨터 > Rust' 카테고리의 다른 글

    댓글