投稿の編集
"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を追加します。
[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に RustcDecodable
と RustcEncodable
の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"]}}