struct <-> String <-> Json

  • 29
    Like
  • 2
    Comment
More than 1 year has passed since last update.

投稿の編集

"Rust Json" で検索するとrust-lang/rustの serialize::json と rust-lang/rust-serializeの rustc-serialize::json の2つが出てきます。どちらを使えばいいのかと思い調べていたら2015年の1月に Confused between serialize and rustc-serialize というissueが立てられていて、今はrustc-serializeを使うのが良いみたいです。
serializeがrustc-serializeより上に表示されるの罠ですね…。

※追記: rustc-serializeはいずれserdeに置き換えたいという話があります。詳細はコメントを参照してください。

rust-serialize::json の基本的な使い方

まずdependencyを追加します。

Cargo.toml
[dependencies]
rustc-serialize = "*"

rustc_serialize::json::encode でJSONにエンコードできます。

extern crate rustc_serialize;

use std::collections::HashMap;
use rustc_serialize::json

fn main() {
    let numeric = 3.14;
    println!("{}", json::encode(&numeric).unwrap());
    // => 3.14

    let str = "Hello world";
    println!("{}", json::encode(&str).unwrap());
    // => "Hello world"

    let opt = Some(3.14);
    println!("{}", json::encode(&opt).unwrap());
    // => 3.14
    let opt: Option<f64> = None;
    println!("{}", json::encode(&opt).unwrap());
    // => null

    let vec = vec!(1939, 1945);
    println!("{}", json::encode(&vec).unwrap());
    // => [1939, 1945]

    let mut map = HashMap::new();
    map.insert("pi", 3.14);
    map.insert("e", 2.71);
    println!("{}", json::encode(&map).unwrap());
    // => {"pi":3.14,"e":2.71}
}

json::decode でその逆を行うことができます。

structとJSONの相互変換を行う

このようなstructがあったとします。

pub struct Person {
    first_name: String,
    last_name: String,
    age: u8,
    address: HashMap<String, String>,
    phone_numbers: Vec<String>
}

このstructを以下のJSONと相互変換を行います。

{
    "first_name": "John",
    "last_name": "Doe",
    "age": 43,
    "address": {
        "city": "London",
        "country": "Great Britain"
    },
    "phone_number": [
        "+44 1234567",
        "+44 2345678"
    ]
}

structをStringに変換する

structに RustcDecodableRustcEncodable のderiveを追加します。

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Person {
    ...
}

structをStringに変換するには json::encode を呼びます。

fn main() {
    let person = Person {
        first_name: "John".to_string(),
        last_name: "Doe".to_string(),
        age: 43,
        address: map![
            "city" => "London",
            "country" => "Great Britain"],
        phone_numbers: vec![
            "+44 1234567".to_string(),
            "+44 2345678".to_string()],
    };

    let encoded = json::encode(&person).unwrap();
    println!("{}", encoded);
}

これを出力すると以下のようになります。

{"age":1,"first_name":"John","last_name":"Doe","address":{"city":"London","country":"Greet Britain"},"phone_numbers":["+44 1234567","+44 2345678"]}

json::decode でstructに戻すことができます。

let decoded: Person = json::decode(&encoded).unwrap();

StringをJsonに変換する

Json::from_str でStringからJsonに変換することができます。

let json = Json::from_str("{\"age\":1,\"first_name\":\"John\",\"last_name\":\"Doe\",\"address\":{\"city\":\"London\",\"country\":\"Greet Britain\"},\"phone_numbers\":[\"+44 1234567\",\"+44 2345678\"]}").unwrap();

println!("first name: {}", json.find("first_name").unwrap());
// => first name: "John"

println!("last name: {}", json.find("last_name").unwrap());
// => last name: "Doe"

println!("age: {}", json.find("age").unwrap());
// => 43

ネストされたオブジェクト

RustcEncodable/RustcDecodableがderiveされたstructや、VecやHashHapなどはToJsonトレイトが実装されています。なので、自分で定義したstructを入れ子にすることができます。

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Person {
    first_name: String,
    last_name: String,
    age: u8,
    phone_numbers: Vec<String>,
    address: HashMap<String, String>,
    image: Image,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Image {
    url: String,
}
json::encode(&person).unwrap();
// => {"first_name":"John","last_name":"Doe","age":43,"phone_numbers":["+44 1234567","+44 2345678"],"image":{"url":"url"}}

json::decode(&person_str).unwrap();
// => Person { first_name: "John", last_name: "Doe", age: 43, phone_numbers: ["+44 1234567", "+44 2345678"], image: Image { url: "url" } }

structをVecやHashMapに入れることもできます。

println!("{}", vec!(person).to_json());
// => [{"address":{"city":"London","country":"Greet Britain"},"age":43,"first_name":"John","last_name":"Doe","phone_numbers":["+44 1234567","+44 2345678"]}]

let mut map = HashMap::new();
map.insert("person".to_string(), person);
println!("{}", map.to_json());
// => {"person":{"address":{"city":"London","country":"Greet Britain"},"age":43,"first_name":"John","last_name":"Doe","phone_numbers":["+44 1234567","+44 2345678"]}}

まとめ

Screen Shot 2015-05-24 at 02.08.41.png