【问题标题】:Get name of enum variant as string with serde使用 serde 将枚举变量的名称作为字符串获取
【发布时间】:2021-04-22 15:07:36
【问题描述】:

我正在尝试获取枚举变体的名称,因为字符串 serde 期望/创建。例如,假设我有以下枚举:

#[derive(Serialize, Deserialize)]
#[serde(rename_all="camelCase")]
pub enum SomeEnum {
    WithoutValue,
    withValue(i32),
}

然后我怎样才能获得变体的 serde 名称?类似的东西

serde::key_name(SomeEnum::WithoutValue) // should be `withoutValue`
serde::key_name(SomeEnum::WithValue)    // should be `withValue`

我可以对serde_json 使用 hack,对于没有值的变体我可以做:

serde_json::to_string(SomeEnum::WithoutValue).unwrap(); // yields `"withoutValue"` with quotation marks

这不是最好的解决方案,因为我需要去掉引号,但在技术上可以工作。

更糟糕的是当枚举变量有值时。它变得更加混乱。

serde_json::to_string(SomeEnum::WithValue(0)).unwrap(); // yields `"{\"second\":0}"

有没有一种干净的方法来实现这一点?我找不到将密钥名称作为字符串获取的 serde API。

【问题讨论】:

  • 值得怀疑,因为重命名的字符串实际上只是 #[derive(Serialize, Deserialize)] 扩展中的硬编码值。你这有什么用?也许还有另一种解决问题的方法。
  • 用例是有一个带有每个枚举变量属性的 js 对象,并且需要使用变量值设置这些属性

标签: rust serde serde-json


【解决方案1】:

一种提取变体信息的稳定但有点样板化的繁重方法是实现自定义Serializer,它从serialize_*_variant 函数中收集变体名称。

这是serde_variant采取的方法。 @Mendy 提到此板条箱仅适用于单元变体。这是自述文件中的示例。

use serde_variant::to_variant_name;

#[derive(Serialize)]
enum Foo {
  Var1,
  #[serde(rename = "VAR2")]
  Var2,
}

assert_eq!(to_variant_name(&Foo::Var1).unwrap(), "Var1");
assert_eq!(to_variant_name(&Foo::Var2).unwrap(), "VAR2");

要提到的另一个缺点是,这只适用于默认的、外部标记的枚举表示。其他表示不使用serialize_*_variant 函数。

【讨论】:

  • 这个库真的很酷,但不适用于具有值的枚举变体,我赞成它,现在删除我的投票为时已晚
  • @Mendy 谢谢,我补充说这是对我的回答的限制。我还解释了serde_variant 在内部是如何工作的。
  • 谢谢@jonasbb
【解决方案2】:

当一个 Enum 变体没有值时,它将被序列化为String,否则它将被序列化为一个以变体名称为键的对象。

基本上,您的 Enum 将按如下方式序列化:

#[derive(Serialize)]
struct MyStruct {
  my_field: SomeEnum,
  some_other_field: String,
};

带有withValue 变体的Json 示例:

{
  "my_field": {
    "withValue": 2
  },
  "some_other_field": "I like turtles"
}

带有WithoutValue 变体的Json 示例:

{
  "my_field": "withoutValue",
  "some_other_field": "Boom goes the dynamite"
}

【讨论】:

  • 我并不打算让我的枚举像 Option,只是想展示从变体有值到没有值的区别
  • @Mendy,明白了。我已经相应地编辑了我的回复。
猜你喜欢
  • 2018-08-16
  • 2021-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-20
  • 2016-09-08
  • 1970-01-01
  • 2013-08-07
相关资源
最近更新 更多