RustでJSONの読み書きを行う
目次
- RustでJSONの読み書き
- 外部ライブラリのインストール
- ライブラリをuseする
- 構造体をシリアライズ/デシリアライズする
- 入れ子になっている構造体をシリアライズ/デシリアライズする
- JSONファイルへの書き込み/読み込み
- おわりに
RustでJSONの読み書き
RustでJSONの読み書きを行う方法をまとめました。
RustではJSONのシリアライズ・デシリアライズは「serde
」という外部ライブラリを使うのが一般的になっています。
このライブラリの使い方を具体的に解説していきます。
外部ライブラリのインストール
外部ライブラリは「serde
」と「serde_json
」をインストールします。
JSONファイルのパースの場合はこの2つが必要ですので注意してください。
で、この2つのライブラリなんですがserde
のインストール方法にコツがあってこれを記載しているドキュメントがほとんどありませんでした。
そのため最終的にGitHubのページで必要な情報を見つけました。
コツというのは↓のようにCargo.toml
を書くことです。
[package] name = "rust_json" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.1"
↑の[dependecies]
の項目の
serde = { version = "1.0", features = ["derive"] }
の部分がコツです。
「features = ["derive"」
」となっている部分に注意してください。
ここの記述が無いとserde
のSerialize
やDeserialize
が使えないです。
ですので必ずこのフォーマットで書くようにしてください。
筆者はこれに気づかず30分ほど時間を溶かしました。
(^ _ ^) | 帰ってこい、30分 |
(・ v ・) | 帰りまてん |
ライブラリをuseする
必要なライブラリをソースコードの先頭でuse
しておきます。
use serde_json; use serde::{Serialize, Deserialize}; use std::io::Write;
serde_json
はJSONへのシリアライズ/デシリアライズで、serde::{Serialize, Deserialize}
は構造体のderive
で必要になります。
std::io::Write
はファイル入出力で必要になります。
構造体をシリアライズ/デシリアライズする
シリアライズというのは構造体を文字列に変換することです。
逆のデシリアライズは文字列を構造体にします。
serde
では↓のようにするとシリアライズとデシリアライズができます。
#[derive(Serialize, Deserialize, Debug)] struct Animal { name: String, age: usize, } fn test_serialize_and_deserialize() { let animal = Animal { name: String::from("Mike"), age: 20 }; let serialized = serde_json::to_string(&animal).unwrap(); println!("serialized: {}", serialized); let deserialized: Animal = serde_json::from_str(&serialized).unwrap(); println!("deserialized: {:?}", deserialized); }
出力結果↓。
serialized: {"name":"Mike","age":20} deserialized: Animal { name: "Mike", age: 20 }
構造体をシリアライズ/デシリアライズするには構造体にderive
を付ける必要があります。
#[derive(Serialize, Deserialize, Debug)] struct Animal { name: String, age: usize, }
こうするとこの構造体をシリアライズ/デシリアライズできるようになります。
構造体をシリアライズするには
let serialized = serde_json::to_string(&animal).unwrap();
のようにserde_json::to_string()
を使います。
こうすると構造体を文字列に変換できます。
デシリアライズするには
let deserialized: Animal = serde_json::from_str(&serialized).unwrap();
このようにserde_json::from_str()
を使います。
入れ子になっている構造体をシリアライズ/デシリアライズする
構造体を入れ子にしたい場合は、つまり複数の構造体で構成したい場合はそれぞれの構造体にすべてderive
を付けます。
#[derive(Serialize, Deserialize, Debug)] struct PTag { content: String, } #[derive(Serialize, Deserialize, Debug)] struct DivTag { p_tags: Vec<PTag>, } fn test_div_tag() { let mut div_tag = DivTag { p_tags: vec![] }; div_tag.p_tags.push(PTag { content: String::from("hige") }); div_tag.p_tags.push(PTag { content: String::from("hoge") }); let serialized = serde_json::to_string(&div_tag).unwrap(); println!("serialized: {}", serialized); let deserialized: DivTag = serde_json::from_str(&serialized).unwrap(); println!("deserialized: {:?}", deserialized); }
出力結果↓。
serialized: {"p_tags":[{"content":"hige"},{"content":"hoge"}]} deserialized: DivTag { p_tags: [PTag { content: "hige" }, PTag { content: "hoge" }] }
↑の場合、DivTag
はPTag
のベクタを持っていますがこれもちゃんとシリアライズされます。
このように構造体を入れ子にするときはそれぞれの構造体にderive
を付けましょう。
JSONファイルへの書き込み/読み込み
シリアライズしたデータのファイルへの書き込み、またはファイルデータのデシリアライズは↓のように行います。
fn test_file() { let animal = Animal { name: String::from("Mike"), age: 20 }; let mut fout = std::fs::OpenOptions::new() .write(true) .create(true) .open("data.json") .unwrap(); let serialized = serde_json::to_string(&animal).unwrap(); fout.write_all(serialized.as_bytes()); let content = std::fs::read_to_string("data.json").unwrap(); let deserialized: Animal = serde_json::from_str(&content).unwrap(); println!("deserialized: {:?}", deserialized); }
出力結果↓。
deserialized: Animal { name: "Mike", age: 20 }
シリアライズしたデータは文字列です。
ですので普通のファイル入出力でファイルにデータを書き込み可能です。
また文字列のデータが書き込まれたファイルを開いてデータを読み込み、それをデシリアライズすれば構造体に変換可能になります。
「構造体 -> 文字列(JSON)-> ファイル -> 文字列(JSON) -> 構造体」
という流れになります。
おわりに
今回はRustでJSONファイルを読み書きする方法を解説しました。
serde
を使うと簡単に読み書きできるので開発もはかどりますね。
(^ _ ^) | シリアライズだ! |
(・ v ・) | デシリアライズだ! |