21

我正在HashMap用 serde 序列化一个,如下所示:

#[derive(Serialize, Deserialize)]
struct MyStruct {
    map: HashMap<String, String>
}

HashMap的键顺序未指定,并且由于散列是随机的(请参阅文档),因此键实际上最终会在相同运行之间以不同的顺序出现。

我希望我HashMap按排序(例如字母)键顺序进行序列化,以便序列化是确定性的。

我可以使用 aBTreeMap而不是 aHashMap来实现这一点,因为BTreeMap::keys()它按排序顺序返回它的键,但我不想仅仅为了适应序列化逻辑而更改我的数据结构。

如何告诉 serdeHashMap在序列化之前对键进行排序?

4

1 回答 1

21

使用serialize_with字段属性

use serde::{Deserialize, Serialize, Serializer}; // 1.0.106
use serde_json; // 1.0.52
use std::collections::{BTreeMap, HashMap};

#[derive(Serialize, Deserialize, Default)]
struct MyStruct {
    #[serde(serialize_with = "ordered_map")]
    map: HashMap<String, String>,
}

fn ordered_map<S>(value: &HashMap<String, String>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    let ordered: BTreeMap<_, _> = value.iter().collect();
    ordered.serialize(serializer)
}

fn main() {
    let mut m = MyStruct::default();
    m.map.insert("gamma".into(), "3".into());
    m.map.insert("alpha".into(), "1".into());
    m.map.insert("beta".into(), "2".into());

    println!("{}", serde_json::to_string_pretty(&m).unwrap());
}

在这里,我选择BTreeMap从 中重建一个整体HashMap,然后重用现有的序列化实现。

{
  "map": {
    "alpha": "1",
    "beta": "2",
    "gamma": "3"
  }
}
于 2017-03-10T16:38:03.640 回答