Rustにおけるデータのシリアライズとデシリアライズは、特にウェブサービス、データベース、またはコンポーネント間のメッセージ交換との統合時に非常に一般的なタスクです。これに最も人気のあるライブラリはserdeで、Rustにおけるシリアライズの事実上の標準となっています。
問題の歴史
Rust開発者は柔軟で高性能なシリアライズの必要性に直面しました。最初は多くの専門的なソリューションが存在しましたが、実際にはserdeがderiveマクロとの便利な統合を提供し、さまざまな形式(JSON、CBOR、BSON、TOML、YAMLなど)のサポートのための柔軟なスキームを提案しました。
問題
Rust構造体をデータ交換形式(例えばJSON)に正しく変換することが必要であり、またその逆も必要です。型安全性を失ったり、「静かなエラー」(silent fail)を引き起こしたりしないようにすることが求められます。問題はしばしばデータ構造の不一致や、サポートされていない型のシリアライズを試みることから生じます。
解決策
構造体のシリアライズには、通常#[derive(Serialize, Deserialize)]を使ってSerializeおよびDeserializeトレイトを実装する必要があります。非標準のケースについては、これらのトレイトを手動で実装するか、シリアライズスキームを制御する属性を利用できます。
コードの例:
use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize, Debug)] struct Person { name: String, age: u8, } fn main() { let data = Person { name: "Bob".into(), age: 32 }; let json = serde_json::to_string(&data).unwrap(); println!("{}", json); let obj: Person = serde_json::from_str(&json).unwrap(); println!("{:?}", obj); }
主な特徴:
Option型のフィールドやデフォルト値を持つフィールドをどのようにシリアライズ/デシリアライズしますか?
デフォルト値を指定するために#[serde(default)]を使用するか、Noneをシリアライズしないために#[serde(skip_serializing_if = "Option::is_none")]を使用できます。
コードの例:
#[derive(Serialize, Deserialize)] struct Config { #[serde(default)] timeout: Option<u32>, }
カスタムフィールドや計算値(例: fn get_hash())を持つ構造体をシリアライズできますか?
はい、ただし、シリアライズされるべきでない場合はそれらのフィールドを#[serde(skip)]でマークする必要があります。また、計算された値をシリアライズしたい場合は、手動でSerialize/Deserializeを実装する必要があります。
Rustの構造体のフィールドがJSONオブジェクトと一致しない場合(フィールドが欠落している、または新しいフィールドが現れた場合)、どうなりますか?
デフォルトではserdeはJSONの余分なフィールドを無視します(厳密モードが有効でない限り)。必須フィールドが欠けている場合(#[serde(default)]が指定されていない場合)、エラーが発生します。
外部JSONが余分なフィールドと欠落したフィールドを持っており、構造体が#[serde(default)]を使用していない場合、
長所:
短所:
#[serde(default)]と#[serde(skip_serializing_if)]を使用し、すべてのフィールドが検証され、余分なフィールドが無視されます。
長所:
短所: