web-dev-qa-db-ja.com

Serdeを使用して、構造体をJSONのキーとして持つHas​​hMapをシリアル化するにはどうすればよいですか?

構造体をキーとして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になりました。最初のコードでエラーが発生するのはなぜですか?

7
YjyJeff

カスタムデータ型を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()
    }
}

遊び場

データ構造が列挙型の場合、FooDisplay実装を変更する必要があります。

2
dotPoozer