这是一种方法:
#[macro_use]extern crate serde_derive; // 1.0.70extern crate serde; // 1.0.70extern crate serde_json; // 1.0.24#[derive(Serialize, Deserialize, Debug)]pub struct MyError { error: String,}#[derive(Serialize, Deserialize, Debug)]pub struct MyAge { age: i32, name: String,}#[derive(Debug)]enum AgeOrError { Age(MyAge), Error(MyError),}impl serde::Serialize for AgeOrError { fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { match self { &AgeOrError::Age(ref my_age) => serializer.serialize_some(my_age), &AgeOrError::Error(ref my_error) => serializer.serialize_some(my_error), } }}enum AgeOrErrorField { Age, Name, Error,}impl<'de> serde::Deserialize<'de> for AgeOrErrorField { fn deserialize<D>(deserializer: D) -> Result<AgeOrErrorField, D::Error> where D: serde::Deserializer<'de>, { struct AgeOrErrorFieldVisitor; impl<'de> serde::de::Visitor<'de> for AgeOrErrorFieldVisitor { type Value = AgeOrErrorField; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "age or error") } fn visit_str<E>(self, value: &str) -> Result<AgeOrErrorField, E> where E: serde::de::Error, { Ok(match value { "age" => AgeOrErrorField::Age, "name" => AgeOrErrorField::Name, "error" => AgeOrErrorField::Error, _ => panic!("Unexpected field name: {}", value), }) } } deserializer.deserialize_any(AgeOrErrorFieldVisitor) }}impl<'de> serde::Deserialize<'de> for AgeOrError { fn deserialize<D>(deserializer: D) -> Result<AgeOrError, D::Error> where D: serde::Deserializer<'de>, { deserializer.deserialize_map(AgeOrErrorVisitor) }}struct AgeOrErrorVisitor;impl<'de> serde::de::Visitor<'de> for AgeOrErrorVisitor { type Value = AgeOrError; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "age or error") } fn visit_map<A>(self, mut map: A) -> Result<AgeOrError, A::Error> where A: serde::de::MapAccess<'de>, { let mut age: Option<i32> = None; let mut name: Option<String> = None; let mut error: Option<String> = None; loop { match map.next_key()? { Some(AgeOrErrorField::Age) => age = map.next_value()?, Some(AgeOrErrorField::Name) => name = map.next_value()?, Some(AgeOrErrorField::Error) => error = map.next_value()?, None => break, } } if let Some(error) = error { Ok(AgeOrError::Error(MyError { error: error })) } else { Ok(AgeOrError::Age(MyAge { age: age.expect("!age"), name: name.expect("!name"), })) } }}fn get_results(ages: &[i32]) -> Vec<AgeOrError> { let mut results = Vec::with_capacity(ages.len()); for &age in ages.iter() { if age < 100 && age > 0 { results.push(AgeOrError::Age(MyAge { age: age, name: String::from("The dude"), })); } else { results.push(AgeOrError::Error(MyError { error: format!("{} is invalid age", age), })); } } results}fn main() { let v = get_results(&[1, -6, 7]); let serialized = serde_json::to_string(&v).expect("Can't serialize"); println!("serialized: {}", serialized); let deserialized: Vec<AgeOrError> = serde_json::from_str(&serialized).expect("Can't deserialize"); println!("deserialized: {:?}", deserialized);}请注意,在反序列化中,我们不能重复使用自动生成的反序列化器,因为:
反序列化是一种将字段流式传输给我们的方法,我们无法 窥视 字符串化的JSON表示并猜测其含义。
我们无权访问
serde::de::Visitor
Serde生成的实现。
我也做了一个捷径,并
panic在错误上加油。在生产代码中,您想返回正确的Serde错误。
另一个解决方案是使所有字段都为可选的合并结构,如下所示:
#[macro_use]extern crate serde_derive; // 1.0.70extern crate serde; // 1.0.70extern crate serde_json; // 1.0.24#[derive(Debug)]pub struct MyError { error: String,}#[derive(Debug)]pub struct MyAge { age: i32, name: String,}#[derive(Serialize, Deserialize, Debug)]pub struct MyAgeOrError { #[serde(skip_serializing_if = "Option::is_none")] age: Option<i32>, #[serde(skip_serializing_if = "Option::is_none")] name: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] error: Option<String>,}impl MyAgeOrError { fn from_age(age: MyAge) -> MyAgeOrError { MyAgeOrError { age: Some(age.age), name: Some(age.name), error: None, } } fn from_error(error: MyError) -> MyAgeOrError { MyAgeOrError { age: None, name: None, error: Some(error.error), } }}fn get_results(ages: &[i32]) -> Vec<MyAgeOrError> { let mut results = Vec::with_capacity(ages.len()); for &age in ages.iter() { if age < 100 && age > 0 { results.push(MyAgeOrError::from_age(MyAge { age: age, name: String::from("The dude"), })); } else { results.push(MyAgeOrError::from_error(MyError { error: format!("{} is invalid age", age), })); } } results}fn main() { let v = get_results(&[1, -6, 7]); let serialized = serde_json::to_string(&v).expect("Can't serialize"); println!("serialized: {}", serialized); let deserialized: Vec<MyAgeOrError> = serde_json::from_str(&serialized).expect("Can't deserialize"); println!("deserialized: {:?}", deserialized);}我对此表示保证,因为它允许Rust结构(例如
MyAgeOrError)匹配JSON的布局。这样,JSON布局就被记录在Rust代码中。



