我有一个 API,要求对象的字段按字母顺序排序,因为必须对结构进行哈希处理。
在 Java/Jackson 中,您可以在序列化器中设置一个标志:MapperFeature.SORT_PROPERTIES_ALPHABETICALLY
。我在 Serde 中找不到类似的东西。
我在用着rmp-serde
(消息包 https://msgpack.org/index.html)。它遵循 JSON 使用的注释和序列化过程,所以我认为它会完全兼容,但是@jonasbb 提供的排序 https://stackoverflow.com/questions/67789198/how-can-i-sort-fields-in-alphabetic-order-when-serializing-with-serde/67792465#67792465不适合它。
该结构具有(很多)嵌套的枚举和结构,必须将其展平才能得到最终表示。我在用着Serialize::serialize
为此,但打电话state.serialize_field
在正确的位置(这样一切都是按字母顺序排列的)是一种痛苦,因为枚举需要一个match
子句,因此必须在不同位置对同一字段多次调用它,并且代码非常难以遵循。
作为可能的解决方案,有两个想法:
-
使用平面表示创建一个新结构,并手动按字母顺序对字段进行排序。
这有点容易出错,因此针对这种扁平结构的编程排序解决方案会很棒。
-
缓冲键值Serialize::serialize
(例如,在BTreeMap
,已排序),并调用state.serialize_field
在最后循环。
问题是这些值似乎必须是类型Serialize
,这不是对象安全的,所以我无法弄清楚如何将它们存储在地图中。
使用 serde 序列化时如何对 HashMap 键进行排序? https://stackoverflow.com/q/42723065/155423类似但不相关,因为我的问题是关于结构体字段/属性的排序。
您没有编写您的目标数据格式。这使得很难找到解决方案,因为有些解决方案可能并不适用于所有情况。
如果您使用 JSON,此代码将有效(除非preserve_order
使用功能标志)。对于 TOML 来说也是如此,通过序列化为toml::Value
作为中间步骤。
该解决方案也适用于其他数据格式,但可能会导致不同的序列化,例如,将数据作为映射而不是类似结构的形式发出。
fn sort_alphabetically<T: Serialize, S: serde::Serializer>(value: &T, serializer: S) -> Result<S::Ok, S::Error> {
let value = serde_json::to_value(value).map_err(serde::ser::Error::custom)?;
value.serialize(serializer)
}
#[derive(Serialize)]
struct SortAlphabetically<T: Serialize>(
#[serde(serialize_with = "sort_alphabetically")]
T
);
#[derive(Serialize, Deserialize, Default, Debug)]
struct Foo {
z: (),
bar: (),
ZZZ: (),
aAa: (),
AaA: (),
}
println!("{}", serde_json::to_string_pretty(&SortAlphabetically(&Foo::default()))?);
因为结构必须被散列
虽然场序是非决定论的根源之一,但还有其他因素。许多格式允许不同数量的空格或不同的表示形式,例如 Unicode 转义\u0066
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)