struct <-> String <-> Json

# 投稿の編集

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

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

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

まずdependencyを追加します。

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

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

```rust
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があったとします。

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

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

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

## structをStringに変換する

structに `RustcDecodable` と `RustcEncodable` のderiveを追加します。

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

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

```rust
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);
}
```

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

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

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

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

## StringをJsonに変換する

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

```rust
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を入れ子にすることができます。

```rust
#[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,
}
```

```rust
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に入れることもできます。

```rust
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](https://qiita-image-store.s3.amazonaws.com/0/179/8c786221-9bfc-9454-68de-ecb2b9f94055.png)