这里有一种方法:
#[macro_use]
extern crate serde_derive; // 1.0.117
extern crate serde; // 1.0.117
extern crate serde_json; // 1.0.59
#[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生成的
serde::de::Visitor
个实现.
我还抄了一条捷径,并查看了错误.在生产代码中,您希望返回正确的Serde错误.
另一个解决方案是使所有字段都是可选的合并 struct ,如下所示:
#[macro_use]
extern crate serde_derive; // 1.0.70
extern crate serde; // 1.0.70
extern 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 struct (例如MyAgeOrError
)与JSON的布局相匹配.这样,JSON布局就会记录在Rust代码中.
另外,最近我倾向于在RawValue的帮助下延迟对可选或动态类型JSON部分的解码.不过,要将它们序列化很难,因为RawValue
是一个借来的版本.例如,为了帮助实现序列化,可以将intern a RawValue
提升到'static
生命周期 :
use serde_json::value::{RawValue as RawJson};
fn intern_raw_json(raw_json: Box<RawJson>) -> &'static RawJson {
use parking_lot::Mutex;
use std::mem::transmute;
static BUF: Mutex<Vec<Pin<Box<RawJson>>>> = Mutex::new(Vec::new());
let buf = BUF.lock();
let raw_json: Pin<Box<RawJson>> = raw_json.into();
let pt: &'static RawJson = {
let pt: &RawJson = &*raw_json;
transmute(pt)
};
buf.push(raw_json);
pt
}
If performance is not an issue, then one can deserialize the dynamic parts into the Value.
Similarly, if using Value
is an option, then custom deserialization can be simplified by implementing TryFrom<Value>
.