gpt4 book ai didi

rust - Serde 能否根据字段的值将 JSON 反序列化为一组类型中的一种?

转载 作者:行者123 更新时间:2023-11-29 07:56:50 26 4
gpt4 key购买 nike

我有一组不同的消息,它们以 JSON 形式传入,可以根据单个字段进行区分,但是每个变体都有不同的辅助字段集合:

#[derive(Debug, Serialize, Deserialize)]
struct MessageOne {
///op will always be "one"
op: String,
x: f64,
y: f64,
}

#[derive(Debug, Serialize, Deserialize)]
struct MessageTwo {
///op will always be "two"
op: String,
a: f64,
b: i64,
}

不同的消息类型被路由到不同的处理函数(例如process_message_oneprocess_message_two 等)。是否有一种优雅或惯用的方式来自动选择正确的消息子类型?目前我已经定义了一个通用消息:

#[derive(Debug, Serialize, Deserialize)]
struct MessageGeneric {
op: String,
}

然后将传入的JSON解析成MessageGeneric,读取op字段然后再次反序列化,在op上匹配选择正确的消息类型。完整示例:

#![allow(unused)]

extern crate serde; // 1.0.78
extern crate serde_json; // 1.0.27

#[macro_use]
extern crate serde_derive;

use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize)]
struct MessageGeneric {
op: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct MessageOne {
///op will always be "one"
op: String,
x: f64,
y: f64,
}

#[derive(Debug, Serialize, Deserialize)]
struct MessageTwo {
///op will always be "two"
op: String,
a: f64,
b: f64,
}

fn process_message_one(m: &MessageOne) {
println!("Processing a MessageOne: {:?}", m);
}

fn process_message_two(m: &MessageTwo) {
println!("Processing a MessageTwo: {:?}", m);
}



fn main() {
let data = r#"{
"op": "one",
"x": 1.0,
"y": 2.0
}"#;

let z: MessageGeneric = serde_json::from_str(data).unwrap();

match z.op.as_ref() {
"one" => {
let zp: MessageOne = serde_json::from_str(data).unwrap();
process_message_one(&zp);
},
"two" => {
let zp: MessageTwo = serde_json::from_str(data).unwrap();
process_message_two(&zp);
},
_ => println!("Unknown Message Type")

}

}

我看过 Serde's enum representations但我不清楚在这种情况下是否/如何应用。传入的消息由外部 API 定义,因此除了知道变体是什么之外,我无法控制它们的内容。

最佳答案

在你的结构 MessageOneMessageTwo 中保留“一”或“二”是没有意义的:如果你已经构造了这个结构,你就已经知道它是否是消息一或消息二。

extern crate serde; // 1.0.78
extern crate serde_json; // 1.0.27

#[macro_use]
extern crate serde_derive;

#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "op")]
enum Message {
#[serde(rename = "one")]
One { x: f64, y: f64 },
#[serde(rename = "two")]
Two { a: f64, b: f64 },
}

fn process_message(message: &Message) {
println!("Processing a : {:?}", message);
}

use serde_json::Error;

fn main() -> Result<(), Error> {
let data = r#"{
"op": "one",
"x": 1.0,
"y": 2.0
}"#;

let message: Message = serde_json::from_str(data)?;
process_message(&message);

let data = r#"{
"op": "two",
"a": 1.0,
"b": 2.0
}"#;

let message: Message = serde_json::from_str(data)?;
process_message(&message);

let data = r#"{
"op": "42",
"i": 1.0,
"j": 2.0
}"#;

let message: Message = serde_json::from_str(data)?;
process_message(&message);
Ok(())
}
Standard Output
Processing a : One { x: 1.0, y: 2.0 }
Processing a : Two { a: 1.0, b: 2.0 }

Standard Error
Error: Error("unknown variant `42`, expected `one` or `two`", line: 2, column: 18)

关于rust - Serde 能否根据字段的值将 JSON 反序列化为一组类型中的一种?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53018165/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com