はじめに
意外と構造体 in 構造体を JSON/YAML パースとセットで扱っている記事がぱっと出てこなかったのでメモ。
パッケージの導入
例によって、 serde を使う。
また、JSON -> serde_json、 YAML -> serde_yaml を使う。
cargo add serde --features="derive"
cargo add serde_json
cargo add serde_yaml
構造体の定義
構造体 in 構造体を作って、JSON/YAML 等からデシリアライズ・シリアライズを行う場合、すべての構造体に対して親の構造体に同じ derive 属性を付ける。
これがないと、エラーを起こす。
逆に、子側で属性が増えるのは問題ない。
main.rs
#[derive(Serialize, Deserialize, Debug)]
struct Person {
firstname: String,
sirname: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct Book {
people: Vec<Person>,
}
エラー例
例えば、Book 側(ここでは親側)のみ derive を付けて、Person 側には付けない状態でコンパイルしようとすると、以下のようなエラーが出力される。
error[E0277]: the trait bound `Person: Serialize` is not satisfied
error[E0277]: the trait bound `Person: Deserialize<'_>` is not satisfied
error[E0277]: `Person` doesn't implement `Debug`
実行部分の実装
main.rs
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::BufReader;
// ここに上記構造体定義
fn main() {
let file_name = "data/sample.json";
let file = File::open(file_name).unwrap();
let reader = BufReader::new(file);
// JSON の場合
let data: Book = serde_json::from_reader(reader).unwrap();
// YAML の場合
let data: Book = serde_yaml::from_reader(reader).unwrap();
println!("{:?}", data);
for person in data.people.iter() {
println!("{} {}", person.firstname, person.sirname);
}
}
まとめ
JSON/YAML 等で構造体を複合的に扱う場合、すべてに属性つけるのを忘れずに~~