我正在用serde连载HashMap,就像这样:

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

HashMap的键顺序是未指定的,因为散列是随机的(参见documentation),所以在相同的运行之间,键的顺序实际上是不同的.

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

我可以使用BTreeMap而不是HashMap来实现这一点,因为BTreeMap::keys()会按排序顺序返回其键,但我不想仅仅为了适应序列化逻辑而更改数据 struct .

如何让serde在序列化之前对HashMap个键进行排序?

推荐答案

使用serialize_with field attribute:

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());
}

在这里,我 Select 从HashMap中重建整个BTreeMap,然后重用现有的序列化实现.

{
  "map": {
    "alpha": "1",
    "beta": "2",
    "gamma": "3"
  }
}

Rust相关问答推荐

为什么Tauri要修改被调用函数的参数名称?

as操作符如何将enum转换为int?

在Rust中创建可变片段的可变片段的最有效方法是什么?

为什么我们不能通过指针算法将Rust原始指针指向任意地址?'

将Vec<;U8&>转换为Vec<;{Float}&>

Rust将String上的迭代器转换为&;[&;str]

如何将 struct 数组放置在另一个 struct 的末尾而不进行内存分段

当我try 使用 SKI 演算中的S I I实现递归时,为什么 Rust 会失败?

从 rust 函数返回 &HashMap

无法将`&Vec>`转换为`&[&str]`

Rust 打包在 .deb 中

在 Rust 中,Weak 如何知道内部值何时被删除?

打印 `format_args!` 时borrow 时临时值丢失

Rust 中 `Option` 的内存开销不是常量

为什么拥有 i32 所有权的函数需要它是可变的?

如何在 Rust 中创建最后一个元素是可变长度数组的 struct ?

Rustfmt 是否有明确类型的选项?

使用 rust-sqlx/tokio 时如何取消长时间运行的查询

需要括号的宏调用中的不必要的括号警告 - 这是编写宏的糟糕方法吗?

当引用不再被borrow 时,Rust 不会得到它