问题
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?
回答1:
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",
}
}
}
回答2:
Fortunately serde
has build-in support for enum type:
//# serde = { version = "1.0.99", features = ["derive"] }
//# serde_json = "1.0.40"
use serde::Deserialize;
#[derive(Deserialize, Debug)]
#[serde(tag = "type")]
enum Data {
A { value: Vec<u32> },
B { value: Vec<Vec<u32>> },
}
fn main() {
let a: Data = serde_json::from_str(r#"{"type": "A", "value": [ 1, 2, 3, 4, 5 ]}"#).unwrap();
let b: Data =
serde_json::from_str(r#"{"type": "B", "value": [[1, 2, 3, 4, 5], [6, 7, 8 ]]}"#).unwrap();
println!("{:?}", a);
println!("{:?}", b);
}
回答3:
This may be a person opinion but I would generally try to avoid serialization / deserialization on enums.
Would this not be close to the same thing in C++?
struct DataValue final{
TypeA(Vec<u32>) final,
TypeB(Vec<Vec<u32>>) final
}
来源:https://stackoverflow.com/questions/57639162/how-to-conditionally-deserialize-json-to-two-different-variants-of-an-enum