LoginSignup
1
0

More than 3 years have passed since last update.

Rust で JSONを読み書きする方法がさっぱり分からん☆(^~^)萎えた☆(^~^)

Last updated at Posted at 2019-04-02

2020-03-01(Sun) 書き直し

次のような JSONファイル を読み込みたいとしよう。

linear-regression-wars.json:

{
    "fightingNations": [
        {
            "name": "Kifuwara-kingdom-1",
            "win": 1230,
            "draw": 0,
            "lose": 770,
            "tanks": {
                "tako2000": {
                    "number": 50,
                    "magazine": "grape5x3-hole3"
                },
                "tako3000": {
                    "number": 200,
                    "magazine": "grape2x4-hole1"
                },
                "tako5000": {
                    "number": 20,
                    "magazine": "grape5x3-hole3"
                }
            }
        },
        {
            "name": "Oton-kingdom-1",
            "win": 770,
            "draw": 0,
            "lose": 1230,
            "tanks": {
                "tako2000": {
                    "number": 50,
                    "magazine": "grape5x3-hole3"
                },
                "tako3000": {
                    "number": 200,
                    "magazine": "grape2x4-hole1"
                },
                "tako5000": {
                    "number": 20,
                    "magazine": "grape5x3-hole3"
                }
            }
        }
    ]
}

Cargo.toml には例えば次のように書いてくれだぜ。

[dependencies]
serde = { version = "^1.0.101", features = ["derive"] }
serde_json = "^1.0.41"

main.rs は次のように書いてくれだぜ。

//!
//! [[Rust] Serdeのシリアライズ/デシリアライズを試してみる](https://dev.classmethod.jp/server-side/language/rust-serde-getting-started/)
//! [Rust】serde_jsonの使い方](https://www.amusement-creators.info/post/articles/advent_calendar/2019/02_0/)
//! [Serialize fields as camelCase](https://serde.rs/attr-rename.html)
//!
extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

#[serde(rename_all = "camelCase")]
#[derive(Deserialize, Debug)]
struct LinearRegressionWars {
    fighting_nations: Vec<FightingNation>,
}

#[derive(Deserialize, Debug)]
struct FightingNation {
    name: String,
    win: u32,
    draw: u32,
    lose: u32,
    tanks: HashMap<String, Tank>,
}

#[derive(Deserialize, Debug)]
struct Tank {
    number: u16,
    magazine: String,
}

fn main() {
    // Open file.
    let mut file = match File::open("./linear-regression-wars.json") {
        Ok(n) => n,
        Err(err) => panic!("File open error. {:?}", err),
    };

    // Read file.
    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Ok(n) => n,
        Err(err) => panic!("File open error. {:?}", err),
    };

    // Desirialize.
    let linear_regression_wars = match serde_json::from_str::<LinearRegressionWars>(&contents) {
        Ok(n) => n,
        Err(err) => panic!("File open error. {:?}", err),
    };

    for fighting_nation in linear_regression_wars.fighting_nations {
        println!("name={}", fighting_nation.name);
        println!(
            "    tank number={}",
            fighting_nation.tank["tako2000"].number
        );
    }

    println!("Info    | Finished.");
}

Output:

name=Kifuwara-kingdom-1
    tank number=50
name=Oton-kingdom-1
    tank number=50
Info    | Finished.

とりあえず こんな感じ。

ここから下は古い記事

新しい方法も追いかけてないし、古い方法でも真似する。

Cargo.toml
[dependencies]
serde = "1.0"
serde_json = "1.0"

とりあえず シリアライズ、デシリアライズの略という serde クレートを使う。
たまには

cargo update

でもしろだぜ。
とりあえず 読み書きしたい JSON を用意しろだぜ☆
わたしは コンピューター囲碁で使ったことがある JSON を用意する。

config.json
{
    "comment": "AI竜星戦2018用設定ファイル",
    "boardSize": 19,
    "boardInit": [
        "+++++++++++++++++++",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+++++++++++++++++++"
    ],
    "sente": "black",
    "rule": "jungo",
    "komiJungo": 6.5,
    "outFile": "C:/MuzudhoDrive/projects_cpp/cgfgoban109_for_kifuwarabe2018_ローカルテスト環境/out.txt",
    "inFile": "C:/MuzudhoDrive/projects_cpp/cgfgoban109_for_kifuwarabe2018_ローカルテスト環境/in.txt"
}

これを読み込んで オブジェクトに一発で入れたいわけだぜ。

config_file.rs
/// 設定ファイル

/// 参考: https://github.com/serde-rs/json |シリアライズ、デシリアライズ。
extern crate serde_json;
use serde_json::Value;

use std::fs::File;
use std::io::Read;

pub struct Config {
    /// コメント。
    pub comment: String,

    /// 何路盤。
    pub board_size: usize,

    /// 大会用 out.txt 局面ファイルへのパス。
    pub out_path: String,

    /// 大会用 in.txt 局面ファイルへのパス。
    pub in_path: String,
}
impl Config {
    pub fn load(path:&str) -> Config {

        let mut file = match File::open(path) {
            Ok(n) => n,
            Err(err) => panic!("File open error. {:?}", err),
        };

        let mut contents = String::new();
        match file.read_to_string(&mut contents) {
            Ok(n) => n,
            Err(err) => panic!("File open error. {:?}", err),
        };

        // https://docs.serde.rs/serde_json/value/enum.Value.html
        let document: Value = match serde_json::from_str(&contents) {
            Ok(n) => n,
            Err(err) => panic!("File open error. {:?}", err),
        };

        Config {
            comment: match document["comment"].as_str() {
                Some(n) => n.to_string(),
                None => "".to_string(),
            },

            board_size: match document["boardSize"].as_i64() {
                Some(n) => n as usize, // FIXME 変換方法が分からん☆(^~^)as使う☆(^~^)
                None => 19usize,
            },

            out_path: match document["outFile"].as_str() {
                Some(n) => n.to_string(),
                None => "".to_string(),
            },

            in_path: match document["inFile"].as_str() {
                Some(n) => n.to_string(),
                None => "".to_string(),
            },
        }
    }
}

よく分からんので こんな感じに書いている。
こんなんでいいのか、さっぱり分からん。

1
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0