如何使用serde序列化/反序列化包含数据的枚举键的HashMap ?



我需要序列化和反序列化HashMap,h,枚举Foo作为JSON的键。Foo的变体包含数据(这里简化为u32,但实际上本身就是枚举):

use serde::{Serialize, Deserialize};
use serde_json;
use std::collections::HashMap;
#[derive(Serialize, Deserialize)]
enum Foo {
A(u32),
B(u32),
}
// Tried several different things here! Just deriving the relevant traits doesn't work.
struct Bar {
h: HashMap<Foo, i32>, // The i32 value type is arbitrary
}
fn main() {
let mut bar = Bar { h: HashMap::new() };
bar.h.insert(Foo::A(0), 1);
// I want to be able to do this
let bar_string = serde_json::to_string(&bar).unwrap();
let bar_deser: Bar = serde_json::from_str(&bar_string).unwrap();
}

由于JSON规范要求键是字符串,我知道我需要自定义Foo的序列化和反序列化方式,当它是h中的一个键时。我尝试了以下方法:

  • 序列化和反序列化的自定义实现(例如在这里接受的答案中)
  • 服务器属性,例如:#[serde(into = "String", try_from = "String")]+实现Into<String> for FooTryFrom<String> for Foo(在这里的答案中描述)
  • 使用'serde_with' crate(也在这里的答案中描述)。

不幸的是,这些都没有成功-在编译成功后,所有这些最终都失败了。

在服务器中实现我想要的东西的好方法是什么,如果有的话?如果没有,我将非常感谢任何解决方法的建议。

附加问题:为什么serde/serde_json在HashMap中用作键时,不为String+反序列化的enum(如Foo)提供默认序列化?

以下是serde_with助手箱中serde_as的工作解决方案:

use serde::{Deserialize, Serialize};
use serde_json;
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
enum Foo {
A(u32),
B(u32),
}
#[serde_with::serde_as]
#[derive(Serialize, Deserialize, Debug)]
struct Bar {
#[serde_as(as = "HashMap<serde_with::json::JsonString, _>")]
h: HashMap<Foo, i32>,
}
fn main() {
let mut bar = Bar { h: HashMap::new() };
bar.h.insert(Foo::A(0), 1);
let bar_string = serde_json::to_string(&bar).unwrap();
let bar_deser: Bar = serde_json::from_str(&bar_string).unwrap();
println!("{:?}", bar);
println!("{}", bar_string);
println!("{:?}", bar_deser);
}
Bar { h: {A(0): 1} }
{"h":{"{"A":0}":1}}
Bar { h: {A(0): 1} }

附加问题:为什么serde/serde_json不提供默认序列化String +反序列化的enum,如Foo,当它被用作HashMap中的键时?

如果你注意到,这些问题大多变成了运行时错误。

这是因为serde实际上确实具有与所有Rust值一起工作的映射的表示。所以serde本身没有能力解决这个问题。

serde_json试图将映射馈送到jsonSerializer时,问题就出现了。是的,如果实现了,这个序列化器确实可以将任何键转换为JSON字符串并返回。

我认为这更多的是一个设计决策,为什么没有这样做。如果JSON只支持字符串键,那么JSON序列化器也应该支持。如果用户想使用其他类型作为键,他应该首先将它们转换为字符串,如上面的代码示例所示。

相关内容

  • 没有找到相关文章

最新更新