🔥
Serdeを用いたRustのjson取り扱いメモ
jsonを扱うためにserde_jsonを色々調べた結果の基本機能サンプルコードを備忘のためメモとして載せておきます。
[serde 1.0.197, serde_json 1.0.115]
前提
Cargo.toml
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
基本的な操作
jsonの変換
文字列<&str>
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Obj1 {
f1: i32,
f2: String,
f3: Obj2,
}
#[derive(Debug, Serialize, Deserialize)]
struct Obj2 {
f4: bool,
f5: Option<u32>,
}
fn main() {
let json = r#"{ "f1": 5 , "f2": "foo" , "f3": { "f4": true , "f5": null } }"#;
let de: Obj1 = serde_json::from_str(json).unwrap();
println!("{:?}", de); // Obj1 { f1: 5, f2: "foo", f3: Obj2 { f4: true, f5: None } }
let se: String = serde_json::to_string(&de).unwrap();
println!("{}", se); // {"f1":5,"f2":"foo","f3":{"f4":true,"f5":null}}
let se: String = serde_json::to_string_pretty(&de).unwrap();
println!("{}", se);
// {
// "f1": 5,
// "f2": "foo",
// "f3": {
// "f4": true,
// "f5": null
// }
// }
let json = r#"[{ "f4": true , "f5": null },{ "f4": false , "f5": 7, "f6": "bar" }]"#;
let de: Vec<Obj2> = serde_json::from_str(json).unwrap();
println!("{:?}", de); // [Obj2 { f4: true, f5: None }, Obj2 { f4: false, f5: Some(7) }]
}
ファイル
コード
use serde::{Serialize, Deserialize};
use std::{path::Path, fs::File, io::{BufReader, BufWriter}};
#[derive(Debug, Serialize, Deserialize)]
struct Obj1 {
f1: i32,
f2: String,
f3: Obj2,
}
#[derive(Debug, Serialize, Deserialize)]
struct Obj2 {
f4: bool,
f5: Option<u32>,
}
fn main() {
// file body is same with r#"{ "f1": 5 , "f2": "foo" , "f3": { "f4": true , "f5": null } }"#
let file = File::open(Path::new("./rsc/foo.json")).unwrap();
let de: Obj1 = serde_json::from_reader(BufReader::new(file)).unwrap();
println!("{:?}", de); // Obj1 { f1: 5, f2: "foo", f3: Obj2 { f4: true, f5: None } }
let file = File::create(Path::new("./rsc/bar.json")).unwrap();
serde_json::to_writer(BufWriter::new(file), &de).unwrap(); // to format, use to_writer_pretty()
// "./rsc/bar.json" is not ended with LF
// {"f1":5,"f2":"foo","f3":{"f4":true,"f5":null}}
}
生文字列<Vec<u8>>
コード
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Obj1 {
f1: i32,
f2: String,
f3: Obj2,
}
#[derive(Debug, Serialize, Deserialize)]
struct Obj2 {
f4: bool,
f5: Option<u32>,
}
fn main() {
let json = r#"{ "f1": 5 , "f2": "foo" , "f3": { "f4": true , "f5": null } }"#.to_string().into_bytes();
let de: Obj1 = serde_json::from_slice(&json).unwrap();
println!("{:?}", de); // Obj1 { f1: 5, f2: "foo", f3: Obj2 { f4: true, f5: None } }
let se: Vec<u8> = serde_json::to_vec(&de).unwrap(); // to format, use to_vec_pretty()
println!("{:?}", se); // [123, 34, 102, 49, 34, 58, 53, 44, 34, 102, 50, 34, 58, ...
}
serde_json::Value列挙体
serde_json::Value列挙体について
-
serde_json::Value
はjsonの値を統合して扱えるようにした列挙体
enum Value {
Null,
Bool(bool),
Number(Number), // i64 or u64 or f64
String(String),
Array(Vec<Value>),
Object(Map<String, Value>),
}
- Number型をRustプリミティブ数値型に変換する方法
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Obj1 {
f1: i32,
}
fn main() {
let json = r#"{ "f1": 5 }"#;
let de: Obj1 = serde_json::from_str(json).unwrap();
let se: serde_json::Value = serde_json::to_value(de).unwrap();
println!("{:?}", se); // Object {"f1": Number(5)}
if let serde_json::Value::Object(map) = se {
map.iter().for_each(|(name, value)| {
println!("{name} : {value:?}"); // f1 : Number(5)
if value.is_i64() { println!("is_i64"); assert_eq!(value.as_i64().unwrap(), 5_i64); }
if value.is_u64() { println!("is_u64"); assert_eq!(value.as_u64().unwrap(), 5_u64); }
if value.is_f64() { println!("is_f64"); assert_eq!(value.as_f64().unwrap(), 5_f64); }
// is_i64
// is_u64
});
}
}
コード
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Obj1 {
f1: i32,
f2: String,
f3: Obj2,
}
#[derive(Debug, Serialize, Deserialize)]
struct Obj2 {
f4: bool,
f5: Option<u32>,
}
fn main() {
let json = r#"{ "f1": 5 , "f2": "foo" , "f3": { "f4": true , "f5": null } }"#;
let de: Obj1 = serde_json::from_str(json).unwrap();
let se: serde_json::Value = serde_json::to_value(de).unwrap();
println!("{:?}", se); // Object {"f1": Number(5), "f2": String("foo"), "f3": Object {"f4": Bool(true), "f5": Null}}
let de: Obj1 = serde_json::from_value(se).unwrap();
println!("{:?}", de); // Obj1 { f1: 5, f2: "foo", f3: Obj2 { f4: true, f5: None } }
}
対応フィールド変更
- 命名規則変更による対応付け
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] // lowercase, UPPERCASE, PascalCase, SCREAMING_SNAKE_CASE, kebab-case, SCREAMING-KEBAB-CASE
// #[serde(rename_all(serialize = "...", deserialize = "..."))] able to specify timing and rule as left
struct Obj1 {
field_name: i32,
}
fn main() {
let json = r#"{ "fieldName": 5 }"#;
let de: Obj1 = serde_json::from_str(json).unwrap();
println!("{:?}", de); // Obj1 { field_name: 5 }
println!("{}", serde_json::to_string(&de).unwrap()); // {"fieldName":5}
}
- 個別指定による対応付け
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Obj1 {
#[serde(rename = "field1")]
// #[serde(rename(serialize = "field_1", deserialize = "field1"))] able to specify timing and name as left
f1: i32,
}
fn main() {
let json = r#"{ "f1": 5 }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json));
// Err(Error("missing field `field1`", line: 1, column: 11))
let json = r#"{ "field1": 5 }"#;
let de: Obj1 = serde_json::from_str(json).unwrap();
println!("{:?}", de); // Obj1 { f1: 5 }
println!("{}", serde_json::to_string(&de).unwrap()); // {"field1":5}
}
フィールドを対象外にする
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Obj1 {
f1: i32,
#[serde(skip)]
f2: i32,
#[serde(skip_deserializing, default = "custom_default")]
f3: i32,
#[serde(skip_serializing)]
f4: i32,
#[serde(skip_serializing_if = "Vec::is_empty")]
f5: Vec<i32>,
}
fn main() {
let json = r#"{ "f1": 1 , "f2": 2 , "f3": 3 , "f4": 4 , "f5": [5, 6] }"#;
let mut de: Obj1 = serde_json::from_str(json).unwrap();
println!("{:?}", de); // Obj1 { f1: 1, f2: 0, f3: -77, f4: 4, f5: [5, 6] }
println!("{}", serde_json::to_string(&de).unwrap()); // {"f1":1,"f3":-77,"f5":[5,6]}
de.f5 = Vec::new();
println!("{}", serde_json::to_string(&de).unwrap()); // {"f1":1,"f3":-77}
}
fn custom_default() -> i32 { -77 }
一部が未知,可変なjsonのDeserialize
jsonにのみフィールドが存在する場合
- 無視される
コード
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 { f1: i32 }
fn main() {
let json = r#"{ "f1": 5 ,"foo": 1 }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 5 }
}
- エラーにしたい場合はattributeを付与する
use serde::Deserialize;
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct Obj1 { f1: i32 }
fn main() {
let json = r#"{ "f1": 5 ,"foo": 1 }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json));
// Err(Error("unknown field `foo`, expected `f1`", line: 1, column: 16))
}
jsonのフィールドが欠損している場合
- 構造体の対応フィールドは
Option::None
となる
コード
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 { f1: i32, f2: Option<i32> }
fn main() {
let json = r#"{ "f1": 5 }"#;
let de: Obj1 = serde_json::from_str(json).unwrap();
println!("{:?}", de); // Obj1 { f1: 5, f2: None }
}
- 欠損フィールドが
Option
型でない場合、エラーとなる
コード
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 { f1: i32, f2: i32 }
fn main() {
let json = r#"{ "f1": 5 }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json));
// Err(Error("missing field `f2`", line: 1, column: 11))
}
- デフォルト値としたい場合はattributeを付与する
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 {
f1: i32,
#[serde(default)]
f2: i32,
#[serde(default = "custom_default")]
f3: i32,
}
fn main() {
let json = r#"{ "f1": 5 }"#;
let de: Obj1 = serde_json::from_str(json).unwrap();
println!("{:?}", de); // Obj1 { f1: 5, f2: 0, f3: -77 }
}
fn custom_default() -> i32 { -77 }
フィールドの型が未知,可変の場合
-
serde_json::Value
型を使用する
コード
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 {
f1: serde_json::Value,
}
fn main() {
let json = r#"{ "f1": 5 }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: Number(5) }
let json = r#"{ "f1": "string" }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: String("string") }
}
- 受け取る可能性のある値をenumで定義し、attributeを付与する
use serde::Deserialize;
#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum Var {
Str(String),
Ary(i32, i32),
}
#[derive(Debug, Deserialize)]
struct Obj1 {
f1: Var,
}
fn main() {
let json = r#"{ "f1": "string" }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json)); // Ok(Obj1 { f1: Str("string") })
let json = r#"{ "f1": [5, -1] }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json)); // Ok(Obj1 { f1: Ary(5, -1) })
let json = r#"{ "f1": true }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json));
// Err(Error("data did not match any variant of untagged enum Var", line: 1, column: 14))
}
いくつかの可変オブジェクト構造を統一的に扱う場合
enumを使用する。
- フィールド名で構造が決定する場合
コード
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 {
f1: i32,
f2: ObjType,
}
#[derive(Debug, Deserialize)]
enum ObjType {
Type1{f3: i32, f4: String},
Type2{f5: bool},
}
fn main() {
let json = r#"{ "f1": 1 , "f2": { "Type1": { "f3": 6 , "f4": "string" }} }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 1, f2: Type1 { f3: 6, f4: "string" } }
let json = r#"{ "f1": 2 , "f2": { "Type2": { "f5": false }} }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 2, f2: Type2 { f5: false } }
let json = r#"{ "f1": 2 , "f2": { "Type3": { "f6": null }} }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap_err());
// Error("unknown variant `Type3`, expected `Type1` or `Type2`", line: 1, column: 27)
let json = r#"[ {"Type1": { "f3": 6 , "f4": "string" }}, {"Type2": { "f5": false }}]"#;
for obj in serde_json::from_str::<Vec<ObjType>>(json).unwrap() {
println!("{:?}", obj);
// Type1 { f3: 6, f4: "string" }
// Type2 { f5: false }
}
}
- 特定のフィールド値で構造が決定する場合
コード
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 {
f1: i32,
f2: ObjType,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "identify_type")]
enum ObjType {
Type1{f3: i32, f4: String},
Type2{f5: bool},
#[serde(other)]
TypeOther
}
fn main() {
let json = r#"{ "f1": 1 , "f2": { "identify_type": "Type1" , "f3": 6 , "f4": "string" } }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 1, f2: Type1 { f3: 6, f4: "string" } }
let json = r#"{ "f1": 2 , "f2": { "identify_type": "Type2" , "f5": false } }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 2, f2: Type2 { f5: false } }
let json = r#"{ "f1": 2 , "f2": { "identify_type": "Type3" , "f6": null } }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 2, f2: TypeOther }
let json = r#"[{ "identify_type": "Type1" , "f3": 6 , "f4": "string" }, { "identify_type": "Type2" , "f5": false }]"#;
for obj in serde_json::from_str::<Vec<ObjType>>(json).unwrap() {
println!("{:?}", obj);
// Type1 { f3: 6, f4: "string" }
// Type2 { f5: false }
}
}
- KeyValue型のKeyでValueの構造が決定する場合
コード
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 {
f1: i32,
f2: ObjType,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "key_field", content = "value_field")]
enum ObjType {
Type1{f3: i32, f4: String},
Type2{f5: bool},
#[serde(other)]
TypeOther
}
fn main() {
let json = r#"{ "f1": 1 , "f2": { "key_field": "Type1" , "value_field": { "f3": 6 , "f4": "string" }} }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 1, f2: Type1 { f3: 6, f4: "string" } }
let json = r#"{ "f1": 2 , "f2": { "key_field": "Type2" , "value_field": { "f5": false }} }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 2, f2: Type2 { f5: false } }
let json = r#"{ "f1": 2 , "f2": { "key_field": "Type3" , "value_field": null } }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 2, f2: TypeOther }
let json = r#"[{ "key_field": "Type1" , "value_field": { "f3": 6 , "f4": "string" }}, { "key_field": "Type2" , "value_field": { "f5": false }}]"#;
for obj in serde_json::from_str::<Vec<ObjType>>(json).unwrap() {
println!("{:?}", obj);
// Type1 { f3: 6, f4: "string" }
// Type2 { f5: false }
}
}
フィールド名が曖昧な場合
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Obj1 {
#[serde(alias = "field_1", alias = "Field1")]
f1: i32,
}
fn main() {
let json = r#"{ "f1": 5 }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 5 }
let json = r#"{ "field_1": 5 }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 5 }
let json = r#"{ "Field1": 5 }"#;
println!("{:?}", serde_json::from_str::<Obj1>(json).unwrap()); // Obj1 { f1: 5 }
}
Discussion