use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
enum Animal {
    Cat(Option<String>),
    Dog(String),
    Bird,
}

fn main() {
    let json_animals = r#"
        [
            {"Cat": "Meow"},
            "Cat",
            {"Dog": "Bark"},
            "Bird"
        ]"#;
    println!("{:?}", serde_json::from_str::<Vec<Animal>>(json_animals).unwrap());
}

我们基本上需要一种方法将"Cat"{"Cat": "cat_name"}都反序列化为Animal.我知道编写一个定制的反序列化程序是可行的,但最好是有一个更干净的解决方案.

我try 了别名&amp;重命名&amp;选项&amp;将CatVariant定义为单独的枚举,以包括这两种情况.这些都不管用,因为Error("invalid type: unit variant, expected newtype variant", line: 5, column: 12)

推荐答案

您可以在没有定制Deserialize实现的情况下做到这一点,但这将需要创建一些额外的类型来处理您的模式中存在的各种备选方案.

因为我们不能直接让Animal为您的模式实现Deserialize,所以我们可以创建另一个表示该模式的类型,然后转换为Animal.#[serde(from = "OtherType")]将允许我们告诉serde"反序列化OtherType,然后将其转换为这种类型."

#[derive(Deserialize, Debug)]
#[serde(from = "AnimalRepr")]
enum Animal {
    Cat(Option<String>),
    Dog(String),
    Bird,
}

那么AnimalRepr是什么样子的呢?它要么是一张 map ,要么是一根线.我们可以使用未标记的枚举来表示这一点.

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum AnimalRepr {
    Animal(AnimalType),
    BareAnimalType(BareAnimalType),
}

所以现在AnimalType将处理 map ,BareAnimalType将处理字符串.

#[derive(Deserialize, Debug)]
enum BareAnimalType {
    Cat,
    Bird,
}

#[derive(Deserialize, Debug)]
enum AnimalType {
    Cat(String),
    Dog(String),
}

现在我们只需要一种将AnimalRepr转换为Animal的方法.我们可以通过将BareAnimalTypeAnimalType都转换为Animal来拆分这种转换,并在转换AnimalRepr时委托进行该转换.

impl From<BareAnimalType> for Animal {
    fn from(value: BareAnimalType) -> Self {
        match value {
            BareAnimalType::Cat => Self::Cat(None),
            BareAnimalType::Bird => Self::Bird,
        }
    }
}

impl From<AnimalType> for Animal {
    fn from(value: AnimalType) -> Self {
        match value {
            AnimalType::Cat(n) => Self::Cat(Some(n)),
            AnimalType::Dog(n) => Self::Dog(n),
        }
    }
}

impl From<AnimalRepr> for Animal {
    fn from(value: AnimalRepr) -> Self {
        match value {
            AnimalRepr::Animal(v) => v.into(),
            AnimalRepr::BareAnimalType(v) => v.into(),
        }
    }
}

把所有这些放在一起,我们得到:

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Debug)]
enum BareAnimalType {
    Cat,
    Bird,
}

impl From<BareAnimalType> for Animal {
    fn from(value: BareAnimalType) -> Self {
        match value {
            BareAnimalType::Cat => Self::Cat(None),
            BareAnimalType::Bird => Self::Bird,
        }
    }
}

#[derive(Deserialize, Debug)]
enum AnimalType {
    Cat(String),
    Dog(String),
}

impl From<AnimalType> for Animal {
    fn from(value: AnimalType) -> Self {
        match value {
            AnimalType::Cat(n) => Self::Cat(Some(n)),
            AnimalType::Dog(n) => Self::Dog(n),
        }
    }
}

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum AnimalRepr {
    Animal(AnimalType),
    BareAnimalType(BareAnimalType),
}

impl From<AnimalRepr> for Animal {
    fn from(value: AnimalRepr) -> Self {
        match value {
            AnimalRepr::Animal(v) => v.into(),
            AnimalRepr::BareAnimalType(v) => v.into(),
        }
    }
}

#[derive(Deserialize, Debug)]
#[serde(from = "AnimalRepr")]
enum Animal {
    Cat(Option<String>),
    Dog(String),
    Bird,
}

fn main() {
    let json_animals = r#"
        [
            {"Cat": "Meow"},
            "Cat",
            {"Dog": "Bark"},
            "Bird"
        ]"#;
    println!("{:?}", serde_json::from_str::<Vec<Animal>>(json_animals).unwrap());
}

其输出:

[Cat(Some("Meow")), Cat(None), Dog("Bark"), Bird]

(Playground)

Json相关问答推荐

我如何知道TJSONNumber是double还是double?

如何在Vega中使标记的符号在鼠标指针悬停时可点击

GO KaZaam转换返回意外结果

Pandas 对REST API的自定义响应

无法使用Jolt变换在嵌套的JSON中提取值

如何使用PowerShell从ExchangeOnline命令执行中获得JSON输出

PowerShell - 将 json 添加到文件内容

如何强制仅有一个元素的数组在JSON中生成方括号

我如何将 JSON 格式与 flutter 一起使用?帮助使用 Gamebanana api

将嵌套的 JSON 对象规范化为 Pandas 数据框

如何使用 gson 调用默认反序列化

python,将Json写入文件

如何从 HttpClient 解析 JSON 字符串?

应该使用什么标头将 GZIP 压缩 JSON 从 Android 客户端发送到服务器?

如何从 mysql 数据库构建 JSON 数组

验证和格式化 JSON 文件

如何创建 JSON 对象 Node.js

在 React 中访问子级的父级状态

Javascript:如何判断 AJAX 响应是否为 JSON

在 iPhone 上解析 JSON 日期