LoginSignup
25
23

More than 5 years have passed since last update.

struct <-> String <-> Json

Last updated at Posted at 2015-05-23

投稿の編集

"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

25
23
2

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
25
23