Rust 데이터 직렬화: Serde 라이브러리 사용법
Rust는 시스템 프로그래밍 언어이기 때문에 데이터를 외부로 안전하게 내보내거나 받아오는 일이 많은데요. 이러한 데이터 직렬화/역직렬화를 위해서 사실상 표준처럼 사용되는 라이브러리가 Serde입니다. 거의 모든 Rust 프로젝트가 사용되는 크레이트(Crate)라고 봐도 과언이 아니죠.
이 글에서는 왜 Serde 라이브러를 어떻게 사용하는지 예제와 함께 살펴보겠습니다.
Serde란?
직렬화는 데이터를 Rust 자료형에서 JSON이나 YAML, TOML 등의 형식으로 변화하는 과정을 의미하고, 역직렬화는 변환된 데이터를 다시 원래대로 Rust 자료형으로 돌려놓는 과정을 의미합니다.
그래서 Serde의 크레이트 이름은 Serialize(직렬화)의 첫 3글자와 Deserialize(역직렬화)의 첫 2글자가 들어있습니다.
Rust 생태계에는 다른 크레이트도 있지만, 직렬화와 역직렬화 부문에서는 Serde가 압도적으로 많이 사용되고 있습니다. Serde는 다양한 데이터 포맷을 지원하며, 컴파일 시점에 많은 오류를 잡아주는 안전성이 탁월합니다. 뿐만 아니라 사용자 정의 자료형에 쉽게 적용할 수 있고 최적화가 잘 되어 있어서 매우 빠른 성능을 자랑합니다.
설치하기
Serde 라이브러리를 사용하려면 보통 serde
크레이트와 특정 형식에 대한 serde_xxx
크레이트를 함께 설치해야합니다.
예를 들어, JSON으로 변환을 해야 한다면 Cargo.toml
파일에 serde
와 serde_json
크레이트를 의존성으로 등록해줍니다.
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
다른 형식에 대한 크레이트는 아래 표를 참조 바랍니다.
포맷 | Crate | 특징 |
---|---|---|
JSON | serde_json |
가장 많이 사용, 웹 API와 호환성 좋음 |
YAML | serde_yaml |
사람이 읽기 좋음, 설정 파일에 적합 |
TOML | toml |
Rust의 기본 설정 포맷 |
MessagePack | rmp-serde |
이진 포맷, 빠르고 용량 작음 |
CBOR | serde_cbor |
IoT, 임베디드 등에서 사용 |
구조체 선언
Serde는 기본적으로 Rust의 원시 자료형의 데이터는 바로 변환이 가능하며, Vector와 HashMap도 지원합니다. 하지만 우리는 보통 비지니스 로직을 구현할 때 복잡한 구조의 데이터를 구조체나 열거형으로 추상화하죠.
serde
크레이트는 좀 더 쉽게 사용자 정의 데이터를 직렬화할 수 있도록 Serialize
와 Deserialize
트레잇(trait)을 제공합니다.
이 두 개의 트레잇을 구조체에 파생 매크로를 애트리뷰트로 붙여주기만 하면, 컴파일 시점에 대상 구조체를 위한 트레잇이 자동으로 구현됩니다.
띠라서 아무런 코드 작성없이 이 구조체의 인스턴스를 상대로 직렬화와 역직렬화를 할 수 있게 됩니다.
우선 3개의 필드로 이루어진 Fruit
라는 간단한 구조체로 선언하고 Serde로 변환 가능하도록 설정해보겠습니다.
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Fruit {
name: String,
count: u8,
is_fresh: bool
}
데이터 직렬화
이제 Fruit
구조체의 인스턴스를 생성한 후 JSON 형식으로 직렬화한 후 다시 Fruit
구조체의 인스턴스 역직렬화해보겠습니다.
JSON 형식으로 직렬화를 하려면 serde_json
크레이트에서 제공하는 to_string
함수를 사용하고,
반대로 역직렬화를 할 때는 from_str
함수를 사용합니다.
use serde_json;
fn main() {
let fruit = Fruit {
name: String::from("Apple"),
count: 10,
is_fresh: true
};
// 직렬화: 구조체 인스턴스 → JSON 문자열
let serialized = serde_json::to_string(&fruit).unwrap();
println!("Serialized: JSON {serialized}");
// 역직렬화: JSON 문자열 → 구조체 인스턴스
let deserialized: Fruit = serde_json::from_str(&serialized).unwrap();
println!("Deserialized: {deserialized:?}");
}
Serialized: JSON {"name":"Apple","count":10,"is_fresh":true}
Deserialized: Fruit { name: "Apple", count: 10, is_fresh: true }
케이스 표기법 변경
직렬화되는 JSON의 케이스 표기법을 일괄적으로 변경하고 싶다면 구조체 위에 #[serde(rename_all = "...")]
애트리뷰트를 붙여주면 됩니다.
Rust에서는 필드명을 snail_case로 하는 관행이 있고, JSON에서는 필드명을 camelCase로 하는 관행이 있기 때문에, 두 단어 이상으로 이루어진 필드명을 처리할 때 매우 유용한 기능입니다.
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Fruit {
name: String,
count: u8,
is_fresh: bool
}
다시 JSON 형식으로 직려화해보면 is_fresh
필드가 isFresh
로 변환되는 것을 볼 수 있습니다.
use serde_json;
fn main() {
let fruit = Fruit {
name: String::from("Apple"),
count: 10,
is_fresh: true
};
let serialized = serde_json::to_string(&fruit).unwrap();
println!("Serialized: JSON {serialized}");
}
Serialized: JSON {"name":"Apple","count":10,"isFresh":true}
필드 애트리뷰트
Serde는 이 밖에도 다양한 필드 애트리뷰트를 통해 기본 직렬화 또는 역직렬화 동작을 유연하게 바꿀 수 있도록 해줍니다.
예를 들어, 직렬화 시 제외시키고 싶은 필드에는 #[serde(skip)]
애트리뷰트를 붙여줍니다.
역직렬화 시 누락된 필드에 기본값을 할당하고 싶을 때는 #[serde(default)]
애트리뷰트를 붙여줍니다.
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Serialize, Deserialize, Debug)]
struct Fruit {
#[serde(default)]
name: String,
#[serde(skip)]
count: u8,
#[serde(rename = "isFresh")]
is_fresh: bool,
}
fn main() {
let fruit = Fruit {
name: String::from("Apple"),
count: 10,
is_fresh: true,
};
let serialized = serde_json::to_string(&fruit).unwrap();
println!("Serialized: JSON {serialized}");
let json = r#"{"isFresh":true}"#;
let deserialized: Fruit = serde_json::from_str(&json).unwrap();
println!("Deserialized: {deserialized:?}");
}
Serialized: JSON {"name":"Apple","isFresh":true}
Deserialized: Fruit { name: "", count: 0, is_fresh: true }
전체 코드
본 포스팅에서 작성한 실습 코드는 Rust Playgrond 확인하시고 직접 실행해보실 수 있습니다.
마무리
지금까지 다양한 예제를 통해서 Serde 라이브러를 어떻게 사용하는지 알아보았습니다. Rust에서 거의 필수로 쓰이는 라이브러리인 만큼 API를 숙지하셔서 프로젝트에서 잘 활용하실 수 있으셨으면 좋겠습니다.