如何有条件地将JSON反序列化为枚举的两个不同变体? [英] How to conditionally deserialize JSON to two different variants of an enum?

查看:75
本文介绍了如何有条件地将JSON反序列化为枚举的两个不同变体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比方说我有如下的JSON数据:

{
  "type": "A",
  "value": [ 1, 2, 3, 4, 5 ]
}

{
  "type": "B",
  "value": [ [ 1, 2, 3, 4, 5 ], [ 6, 7, 8 ] ]
}

type确定value的类型,在第一个示例中为Vec<u32>,在第二个示例中为Vec<Vec<u32>>.

如果我将上述数据表示如下:

 enum DataValue {
  TypeA(Vec<u32>),
  TypeB(Vec<Vec<u32>>)
}

struct Data {
  data_type: String,
  value: DataValue
}
 

如何实现Serde反序列化以正确解码这些值?

解决方案

如果您为Serde提供了足够的信息来知道如何执行此操作,则可以直接将JSON数据反序列化为DataValue的实例:

#[derive(Debug, Deserialize)]
#[serde(tag = "type", content = "value")]
enum DataValue {
    #[serde(rename = "A")]
    TypeA(Vec<u32>),
    #[serde(rename = "B")]
    TypeB(Vec<Vec<u32>>),
}

let data_a = r#"
    {
        "type": "A",
        "value": [1, 2, 3, 4, 5]
    }"#;
let a: DataValue = serde_json::from_str(data_a)?;

游乐场

如果将枚举变量命名为AB,则可以省略#[serde(rename = "…")]属性.

这种枚举序列的方式称为相邻标记".您可以在有关枚举序列化的Serde文档中了解有关标记枚举的各种选项.. >

您的Data结构包含一个冗余的附加标签data_type.该信息已经在枚举中进行了编码,因此我认为您不需要此信息.如果您需要将此信息作为字符串,则可以将方法添加到枚举中:

impl DataValue {
    fn variant_name(&self) -> &'static str {
        match self {
            DataValue::TypeA(_) => "A",
            DataValue::TypeB(_) => "B",
        }
    }
}

Let's say I have JSON data like the following:

{
  "type": "A",
  "value": [ 1, 2, 3, 4, 5 ]
}

{
  "type": "B",
  "value": [ [ 1, 2, 3, 4, 5 ], [ 6, 7, 8 ] ]
}

type determines the type of value, which in the first example is Vec<u32> and in the second is Vec<Vec<u32>>.

If I represent the above data as follows:

enum DataValue {
  TypeA(Vec<u32>),
  TypeB(Vec<Vec<u32>>)
}

struct Data {
  data_type: String,
  value: DataValue
}

How do I implement serde deserialization to properly decode these values?

解决方案

You can deserialize your JSON data directly to an instance of DataValue if you give Serde enough information to know how to do this:

#[derive(Debug, Deserialize)]
#[serde(tag = "type", content = "value")]
enum DataValue {
    #[serde(rename = "A")]
    TypeA(Vec<u32>),
    #[serde(rename = "B")]
    TypeB(Vec<Vec<u32>>),
}

let data_a = r#"
    {
        "type": "A",
        "value": [1, 2, 3, 4, 5]
    }"#;
let a: DataValue = serde_json::from_str(data_a)?;

Playground

If you name your enum variants A and B, you can omit the #[serde(rename = "…")] attributes.

This way of serializing enums is called "adjacent tagging". You can learn about the various options of tagging enums in the Serde documentation on enum serialization.

Your Data struct contains a redundant additional tag data_type. This information is already encoded in the enum, so I don't think you need this. If you need this information as a string, you can add a method to the enum:

impl DataValue {
    fn variant_name(&self) -> &'static str {
        match self {
            DataValue::TypeA(_) => "A",
            DataValue::TypeB(_) => "B",
        }
    }
}

这篇关于如何有条件地将JSON反序列化为枚举的两个不同变体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆