Как отсортировать ключи HashMap при сериализации с помощью serde?

Я сериализую HashMap с помощью serde, вот так:

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

Порядок ключей HashMap не указан, а поскольку хеширование является случайным (см. документацию), ключи фактически выходят в разном порядке между одинаковыми запусками.

Я бы хотел, чтобы мой HashMap был сериализован в отсортированном (например, в алфавитном) порядке ключей, чтобы сериализация была детерминированной.

Для этого я мог бы использовать BTreeMap вместо HashMap, поскольку BTreeMap::keys() возвращает свои ключи в отсортированном порядке, но я бы предпочел не изменять структуру данных только для того, чтобы приспособиться к логике сериализации.

Как мне сказать serde отсортировать HashMap ключи перед сериализацией?


person Jo Liss    schedule 10.03.2017    source источник
comment
Примечание: вас может заинтересовать OrderMap bluss, HashMap, порядок итераций которого зависит исключительно от порядка в какие элементы были вставлены и удалены.   -  person Matthieu M.    schedule 10.03.2017


Ответы (1)


Используйте атрибут serialize_with field:

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"
  }
}
person Shepmaster    schedule 10.03.2017