構造体をキーとしてHashMap
をシリアル化したい:
extern crate serde_json; // 1.0.22
#[macro_use]
extern crate serde_derive; // 1.0.68
use std::collections::HashMap;
fn main() {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
struct Foo {
x: u64,
}
#[derive(Serialize, Deserialize, Debug)]
struct Bar {
x: HashMap<Foo, f64>,
}
let mut p = Bar { x: HashMap::new() };
p.x.insert(Foo { x: 0 }, 0.0);
let serialized = serde_json::to_string(&p).unwrap();
}
このコードはコンパイルされますが、実行するとエラーが発生します。
Error("key must be a string", line: 0, column: 0)'
私はコードを変更しました:
#[derive(Serialize, Deserialize, Debug)]
struct Bar {
x: HashMap<u64, f64>,
}
let mut p = Bar { x: HashMap::new() };
p.x.insert(0, 0.0);
let serialized = serde_json::to_string(&p).unwrap();
HashMap
のキーは、文字列ではなくu64
になりました。最初のコードでエラーが発生するのはなぜですか?
カスタムデータ型をJSON(またはその他の形式)にシリアル化するには、Serialize
トレイトを実装する必要があります。そうでない場合、Serdeは型をシリアル化する方法を知りません。
それはこれらの線に沿って何か行くはずです:
impl Display for Foo {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "{}", self.x)
}
}
impl Serialize for Bar {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(self.x.len()))?;
for (k, v) in &self.x {
map.serialize_entry(&k.to_string(), &v)?;
}
map.end()
}
}
( 遊び場 )
データ構造が列挙型の場合、Foo
のDisplay
実装を変更する必要があります。