微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将 serde_json 与像枚举这样的联合类型一起使用?

如何解决如何将 serde_json 与像枚举这样的联合类型一起使用?

我有两个结构,我想使用标记作为 JSON 中的 "type" 字段进行序列化/反序列化,就像这样。

#[derive(Debug,Clone,Serialize,Deserialize)]
#[serde(tag = "type")]
struct ThingA {
    value: usize,}

#[derive(Debug,Deserialize)]
#[serde(tag = "type")]
struct ThingB {
    value: usize,}

这些按预期序列化。例如,

let a = ThingA { value: 0 };
println!("{}",serde_json::to_string(&a)?);
// This yields the expected result:
// {"type":"ThingA","value":0}

但是,当我尝试添加一个枚举作为结构的联合类型时遇到了麻烦。

#[derive(Debug,Deserialize)]
#[serde(tag = "type")]
enum Thing {
    ThingA(ThingA),ThingB(ThingB),}

上面的定义适用于反序列化 JSON,但在序列化过程中添加一个额外的字段。

let json = r#"{"type": "ThingB","value": 0}"#;
let thing: Thing = serde_json::from_str(json)?;
// Correctly parses to:
// ThingB(ThingB { value: 0 })

println!("{}",serde_json::to_string(&thing)?);
// Incorrectly serializes with an extra "type" field:
// {"type":"ThingB","type":"ThingB","value":0}

#[serde(tag = "type")] 枚举上将 #[serde(untagged)] 更改为 Thing 会导致相反的问题:Thing 实例正确序列化,但不再正确解析。

我的目标是让 JSON {"type": "ThingB",value: 0} 在反序列化期间评估为 Thing::ThingB(ThingB {value: 0}),反之亦然,但前提是我反序列化为 Thing。如果我有一个未包装的 ThingB,例如 ThingB {value: 0},我希望它也序列化为 {"type": "ThingB",value: 0}

所以我的问题是:有没有办法分配 serde taguntagged 属性,使它们仅在序列化/反序列化期间应用(类似于 serde 的 rename)?如果没有,有关如何实施 Serialize 和/或 Deserialize 以实现我的目标的任何建议?

解决方法

您可以只在 tag 枚举中使用 Thing,其他的保持干净:

use serde::{Serialize,Deserialize}; // 1.0.124
use serde_json; // 1.0.64

#[derive(Debug,Clone,Serialize,Deserialize)]
struct ThingA {
    value: usize,}

#[derive(Debug,Deserialize)]
struct ThingB {
    value: usize,Deserialize)]
#[serde(tag = "type")]
enum Thing {
    ThingA(ThingA),ThingB(ThingB),}

fn main() {
    let json = r#"{"type": "ThingB","value": 0}"#;
    let thing: Thing = serde_json::from_str(json).unwrap();
    println!("{}",serde_json::to_string(&thing).unwrap());

}

Playground

按照评论中的要求。 如果我们想要同时标记(枚举和结构),我们需要使用包装器和 serde 制作一些 with abracadabra。可以找到更多信息here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。