Rust/프로젝트

Rust로 백엔드 개발기(feat. 메이플스토리) - 07 Null 제외하는 방법

lms0806 2025. 3. 31. 20:55
728x90

이번 시간에는 몇가지 기능을 추가 개발하면서, rust에는 없는 null관련 데이터를 가져오는 방법에 대해 배워보도록 하겠습니다.

 

rust에는 null이 없지만 response로 받은 json에 null값이 포함되어 있는 경우에 대하여 대처할 수 있습니다.

방법 1 Option

rust에는 Option이라는 함수를 통하여 해당 값이 있는 경우와 없는 경우로 나눠서 체크할 수 있습니다.

 

다음과 같이 skill에 대한 정보를 불러오는 구조체가 있다고 생각해봅시다.

pub struct SkillInfo {
    pub skill_name: String,
    pub skill_description: String,
    pub skill_level: i8,
    pub skill_effect: Option<String>,
    pub skill_icon: String,
    pub skill_effect_next: Option<String>,
}

#[derive(Deserialize, Serialize, Debug)]
pub struct CharacterSkill {
    pub character_skill: Vec<SkillInfo>,
}

skill_effect에 값으로 null이 올 수 있으므로 Option<String>으로 만들어줍니다.

 

이후 다음과 같이 값을 요청받은 결과를 받아오게 된 경우, null이 포함될 수 있습니다.

let user_character_skill: CharacterSkill = response
    .json()
    .await
    .expect("Failed to parse response JSON");

그런 경우 다음과 같이 filter를 활용하여 처리가 가능합니다.

let filter_character_skill: CharacterSkill = CharacterSkill {
    character_skill: user_character_skill
        .character_skill
        .into_iter()
        .map(|skill| SkillInfo {
            skill_name: skill.skill_name,
            skill_description: skill.skill_description,
            skill_level: skill.skill_level,
            skill_effect: Some(skill.skill_effect.unwrap_or_default()),
            skill_icon: skill.skill_icon,
            skill_effect_next: Some(skill.skill_effect_next.unwrap_or_default()),
        })
        .collect(),
};

Some(skill.skill_effect.unwrap_or_default()) 만약 어떠한 값이 있다면 그 값을 넣고, 아닌 경우 unwrap_or_default()를 통해 기본값으로 만들 수 있습니다.

 

그러나, 이렇게 하는 경우, 값으로 받아온 객체 뿐만 아니라 새로운 객체를 만들어서 반환하기 때문에 메모리적으로 불리하게 작동할 수 있습니다.

 

그렇다면 어떤 방법이 있을까요?

방법 2 serde_as (추천)

serde_as라는 외부 라이브러리를 통하여 같은 결과를 받아올 수 있습니다.

#[serde_as]
#[derive(Deserialize, Serialize, Debug)]
pub struct SkillInfo {
    pub skill_name: String,
    pub skill_description: String,
    pub skill_level: i8,
    #[serde_as(deserialize_as = "DefaultOnNull")]
    pub skill_effect: String,
    pub skill_icon: String,
    #[serde_as(deserialize_as = "DefaultOnNull")]
    pub skill_effect_next: String,
}

#[derive(Deserialize, Serialize, Debug)]
pub struct CharacterSkill {
    pub character_skill: Vec<SkillInfo>,
}

다음과 같이 skill_effectOption<String>대신 String으로 주어지고, #[serde_as(deserialize_as = "DefaultOnNull")]와 같은 태그를 붙여 만약 null인 경우 ""으로 치환하도록 해줍니다.

 

그러면 기존에 .filter()를 활용해서 만들던 로직을 수행하지 않아도 같은 결과를 만들어낼 수 있습니다.

 

다음 시간에는 user_ocid 값을 어떻게 사용자별로 사용하여 api를 호출할 수 있는지에 대해 다뤄보고자 합니다.

728x90