🔥

Serdeを用いたRustのjson取り扱いメモ

2024/04/15に公開


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 } }
}

対応フィールド変更

  1. 命名規則変更による対応付け
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}
}
  1. 個別指定による対応付け
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 }

フィールドの型が未知,可変の場合

  1. 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") }
}
  1. 受け取る可能性のある値を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を使用する。

  1. フィールド名で構造が決定する場合
コード
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 }
    }
}
  1. 特定のフィールド値で構造が決定する場合
コード
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 }
    }
}
  1. 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