使用 "Serde" 反序列化时可以映射类型吗?
Can I map types when deserializing with "Serde"?
基本上我有以下数据结构:
enum Value {
Scalar(f64),
Vector3((f64, f64, f64)),
}
struct Data {
attribute: Value,
}
使用 serde/serde_json 序列化得到以下内容
{
"attribute": { "Scalar": 1.0 }
}
{
"attribute": { "Vector3": [ 1.0, 2.0, 3.0 ] }
}
反序列化按预期工作。但是,是否可以将以下内容反序列化为相同的数据结构?
{
"attribute": 1.0
}
{
"attribute": [ 1.0, 2.0, 3.0 ]
}
是否可以将 f64
映射到 Scalar(f64)
并将 Vec<f64>
映射到 Vector3((f64, f64, f64))
?
两种形式都应该有效。如果以下最小示例有效,那就太好了:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
enum Value {
Scalar(f64),
Vector3((f64, f64, f64)),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
struct Data {
attribute: Value,
}
fn main() {
let js1 = r#"
{
"attribute": { "Scalar": 1.0 }
}"#;
let d1: Data = serde_json::from_str(js1).unwrap();
println!("{:?}", d1);
let js2 = r#"
{
"attribute": { "Vector3": [ 1.0, 2.0, 3.0 ] }
}"#;
let d2: Data = serde_json::from_str(js2).unwrap();
println!("{:?}", d2);
let js3 = r#"
{
"attribute": 1.0
}"#;
let d3: serde_json::Result<Data> = serde_json::from_str(js3);
match d3 {
Ok(d3) => println!("{:?}", d3),
Err(e) => println!("{:?}", e),
}
let js4 = r#"
{
"attribute": [ 1.0, 2.0, 3.0 ]
}"#;
let d4: serde_json::Result<Data> = serde_json::from_str(js4);
match d4 {
Ok(d4) => println!("{:?}", d4),
Err(e) => println!("{:?}", e),
}
}
输出:
Data { attribute: Scalar(1.0) }
Data { attribute: Vector3((1.0, 2.0, 3.0)) }
Error("expected value", line: 3, column: 22)
Error("expected value", line: 3, column: 22)
您可以在您的枚举上使用 #[serde(untagged)]
以允许它被“映射”。 Serde doesn't currently support both at the same time but there is a hack here 虽然我没试过。您还可以在 variant
中有一个带有标记名称的枚举
示例:
#[serde(untagged)]
enum Value {
Scalar(f64),
ScalarTagged {Scalar: f64},
Vector3((f64, f64, f64)),
Vector3Tagged {
Vector3: (f64, f64, f64)
}
}
这通过了你的最小示例
@Raspberry1111 提出了一个广受欢迎的解决方法。但是,仍然欢迎更直接的解决方案。
我不得不使用 #[serde (untagged)]
(参见 Enum representations)并更改数据结构以满足我的所有需求:
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
enum TaggedValue {
Scalar(f64),
Vector3((f64, f64, f64)),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
enum Value {
Scalar(f64),
Vector3((f64, f64, f64)),
Tagged(TaggedValue),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
struct Data {
attribute: Value,
}
// [...]
输出:
Data { attribute: Tagged(Scalar(1.0)) }
Data { attribute: Tagged(Vector3((1.0, 2.0, 3.0))) }
Data { attribute: Scalar(1.0) }
Data { attribute: Vector3((1.0, 2.0, 3.0)) }
仍然欢迎任何更直接的解决方案
基本上我有以下数据结构:
enum Value {
Scalar(f64),
Vector3((f64, f64, f64)),
}
struct Data {
attribute: Value,
}
使用 serde/serde_json 序列化得到以下内容
{
"attribute": { "Scalar": 1.0 }
}
{
"attribute": { "Vector3": [ 1.0, 2.0, 3.0 ] }
}
反序列化按预期工作。但是,是否可以将以下内容反序列化为相同的数据结构?
{
"attribute": 1.0
}
{
"attribute": [ 1.0, 2.0, 3.0 ]
}
是否可以将 f64
映射到 Scalar(f64)
并将 Vec<f64>
映射到 Vector3((f64, f64, f64))
?
两种形式都应该有效。如果以下最小示例有效,那就太好了:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
enum Value {
Scalar(f64),
Vector3((f64, f64, f64)),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
struct Data {
attribute: Value,
}
fn main() {
let js1 = r#"
{
"attribute": { "Scalar": 1.0 }
}"#;
let d1: Data = serde_json::from_str(js1).unwrap();
println!("{:?}", d1);
let js2 = r#"
{
"attribute": { "Vector3": [ 1.0, 2.0, 3.0 ] }
}"#;
let d2: Data = serde_json::from_str(js2).unwrap();
println!("{:?}", d2);
let js3 = r#"
{
"attribute": 1.0
}"#;
let d3: serde_json::Result<Data> = serde_json::from_str(js3);
match d3 {
Ok(d3) => println!("{:?}", d3),
Err(e) => println!("{:?}", e),
}
let js4 = r#"
{
"attribute": [ 1.0, 2.0, 3.0 ]
}"#;
let d4: serde_json::Result<Data> = serde_json::from_str(js4);
match d4 {
Ok(d4) => println!("{:?}", d4),
Err(e) => println!("{:?}", e),
}
}
输出:
Data { attribute: Scalar(1.0) }
Data { attribute: Vector3((1.0, 2.0, 3.0)) }
Error("expected value", line: 3, column: 22)
Error("expected value", line: 3, column: 22)
您可以在您的枚举上使用 #[serde(untagged)]
以允许它被“映射”。 Serde doesn't currently support both at the same time but there is a hack here 虽然我没试过。您还可以在 variant
示例:
#[serde(untagged)]
enum Value {
Scalar(f64),
ScalarTagged {Scalar: f64},
Vector3((f64, f64, f64)),
Vector3Tagged {
Vector3: (f64, f64, f64)
}
}
这通过了你的最小示例
@Raspberry1111 提出了一个广受欢迎的解决方法。但是,仍然欢迎更直接的解决方案。
我不得不使用 #[serde (untagged)]
(参见 Enum representations)并更改数据结构以满足我的所有需求:
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
enum TaggedValue {
Scalar(f64),
Vector3((f64, f64, f64)),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
enum Value {
Scalar(f64),
Vector3((f64, f64, f64)),
Tagged(TaggedValue),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
struct Data {
attribute: Value,
}
// [...]
输出:
Data { attribute: Tagged(Scalar(1.0)) }
Data { attribute: Tagged(Vector3((1.0, 2.0, 3.0))) }
Data { attribute: Scalar(1.0) }
Data { attribute: Vector3((1.0, 2.0, 3.0)) }
仍然欢迎任何更直接的解决方案