🌊

RustでJSONをファイルに書いたり読んだりする

2021/08/29に公開

いやあの、Rustを勉強中でして、serdeを使ってStructHashMapが絡むようなやつをJSONにしてファイルに書いたり読んだりするのがやりたかっただけなのですが、意外と時間かかったのでメモっときます。

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::io::BufReader;

#[derive(Serialize, Deserialize, Debug)]
struct Memo {
    id: isize,
    body: String,
    star: bool,
}

type Memos = HashMap<String, Memo>;

fn main() {
    write_file("hello".to_string());
    read_file();
}

fn write_file(body: String) -> std::io::Result<()> {
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .open("memo.json")?;
    println!("file: {:#?}", file);

    let memo = Memo {
        id: 100,
        body: body,
        star: true,
    };

    let mut memos = HashMap::new();
    memos.insert(memo.id.to_string(), memo);

    let memos_text = serde_json::to_string(&memos).unwrap();
    println!("memos: {}", &memos_text);
    write!(&file, "{}", memos_text)?;

    Ok(())
}

fn read_file() -> std::io::Result<()> {
    let mut memos_file = OpenOptions::new()
        .read(true)
        .write(true)
        .open("memo.json")?;
    let reader = BufReader::new(memos_file);
    let memos: Memos = serde_json::from_reader(reader)?;
    println!("memo_text: {:?}", memos);
    Ok(())
}

どこでハマったかというと、JSONとかSerdeとかいうよりは、ファイルに書き込むところのwrite!(&file, "{}", memos_text)です。ファイルに書き込んだJSONの"がどうやっても\でエスケープされてしまって、テキストになるんで、次に読み込む時にdeserializeしにくいという内容

serde_json::to_writer(&file, &memos_text)?;
// => "{\"100\":{\"id\":100,\"body\":\"hello\",\"star\":true}}"

write!(&file, "{:?}", memos_text)?;
// => "{\"100\":{\"id\":100,\"body\":\"hello\",\"star\":true}}"

write!(&file, "{}", memos_text)?;
// => {"100":{"id":100,"body":"hello","star":true}} やった! 

最後の行に行き着くまでにそこそこ時間が溶けました。{:?}って単なるフォーマッターかと思ってたけどエスケープとかしてくるのか、っていうだけのお話し。

Discussion