🦀

【Rust】serde_jsonあれこれ

に公開

はじめに

rustお勉強2日目の初心者なので、温かい目で見守ってください。
間違いがあればコメントで指摘していただけると助かります。

serde_json - Rustdocs

https://docs.serde.rs/serde_json/

jsonのキーに予約語に使われているとき〜

こんな感じのjsonがあるとする。

{
    "type": "hogehoge"
}

↓のような構造体に変換したい。
でも、typeって予約語。。。。

struct Fuga{
    type: String,
}

とりあえず書いてみるが、コンパイルは通らない
うん、知ってた。

src/main.rs
extern crate serde_json;

use serde_derive::Deserialize;

#[derive(Deserialize, Debug)]
struct Fuga {
    type: String,
}

fn main() {
    let json_str = r#"
    {
        "type": "hogehoge"
    }
    "#;
    let fuga: Fuga = serde_json::from_str(json_str).unwrap();
    println!("{:?}", fuga);
}

対処法その1

Raw identifiers を使用する。

実は、上記のコードを cargo run すると、こんなエラーが出てくる。

error: expected identifier, found keyword `type`
 --> src/main.rs:7:5
  |
7 |     type: String,
  |     ^^^^ expected identifier, found keyword
  |
help: you can escape reserved keywords to use them as identifiers
  |
7 |     r#type: String,
  |     ^^^^^^

help まで出してくれるなんて、優しい。
ということで、さきほどの構造体を↓のように書き換えて実行する。

struct Fuga {
    r#type: String,
}
$ cargo run
Fuga { type: "hogehoge" }

よしよし。

対処法その2

構造体のフィールドの名前を変えちゃう!

該当のフィールドの上に、これをつけるだけ。

#[serde(rename = "jsonのキー")]

Field attributes に詳しく書いてある。

ということで、構造体を↓のように書き換えて実行する。

struct Fuga {
    #[serde(rename = "type")]
    type_name: String,
}
$ cargo run
Fuga { type_name: "hogehoge" }

よしよし。

jsonのキーがキャメルやアッパーのとき〜

こんな感じのjsonがあるとする。

{
    "Type": "hogehoge"
}

構造体にするとしたら、こう??

struct Fuga{
    Type: String,
}

いいえ。

さきほどの Field attributes を使いましょう。

struct Fuga {
    #[serde(rename = "Type")]
    r#type: String,
}
src/main.rs
extern crate serde_json;

use serde_derive::Deserialize;

#[derive(Deserialize, Debug)]
struct Fuga {
    #[serde(rename = "Type")]
    r#type: String,
}

fn main() {
    let json_str = r#"
    {
        "Type": "hogehoge"
    }
    "#;
    let fuga: Fuga = serde_json::from_str(json_str).unwrap();
    println!("{:?}", fuga);
}
$ cargo run
Fuga { type: "hogehoge" }

よしよし。

ちなみに、キャメルでもできなくはない。
が、warning が出るのでよろしくない。

warning: structure field `Type` should have a snake case name
 --> src/main.rs:7:5
  |
7 |     Type: String,
  |     ^^^^
  |
  = note: `#[warn(non_snake_case)]` on by default
help: rename the identifier or convert it to a snake case raw identifier
  |
7 |     r#type: String,
  |     ^^^^^^

warning: 1 warning emitted

最後に

キャメル、アッパーのところ
もう一つ、やり方があった気がしたけど、忘れちゃった。。。
思い出したら追記します。

Discussion