Bene, ecco un modo di fare che:
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
#[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 serde::Deserialize for AgeOrErrorField {
fn deserialize<D>(deserializer: D) -> Result<AgeOrErrorField, D::Error>
where D: serde::Deserializer
{
struct AgeOrErrorFieldVisitor;
impl serde::de::Visitor 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(AgeOrErrorFieldVisitor)
}
}
impl serde::Deserialize for AgeOrError {
fn deserialize<D>(deserializer: D) -> Result<AgeOrError, D::Error>
where D: serde::Deserializer
{
deserializer.deserialize_map(AgeOrErrorVisitor)
}
}
struct AgeOrErrorVisitor;
impl serde::de::Visitor for AgeOrErrorVisitor {
type Value = AgeOrError;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "age or error")
}
fn visit_map<V>(self, mut visitor: V) -> Result<AgeOrError, V::Error>
where V: serde::de::MapVisitor
{
let mut age: Option<i32> = None;
let mut name: Option<String> = None;
let mut error: Option<String> = None;
loop {
match try!(visitor.visit_key()) {
Some(AgeOrErrorField::Age) => age = try!(visitor.visit_value()),
Some(AgeOrErrorField::Name) => name = try!(visitor.visit_value()),
Some(AgeOrErrorField::Error) => error = try!(visitor.visit_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
}
pub 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);
}
Si noti che in deserializzazione non possiamo riutilizzare i deserializzatore generati automaticamente, perché:
a) deserializzazione è una specie di in streaming i campi a noi, impossibile sbirciare nella rappresentazione JSON con stringa e indovinare cosa è;
b) non abbiamo accesso alle implementazioni serde::de::Visitor
generate da Serde.
Inoltre ho fatto una scorciatoia e panick
su errori. Nel codice di produzione dovresti invece restituire gli errori Serde corretti.
Un'altra soluzione sarebbe quella di fare una struttura fusa con tutti i campi facoltativi, come questo:
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
#[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
}
pub 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);
}
avrei garantire per questo perché consente alla struttura di Rust (ad es) da abbinare il layout del tuo JSON. In questo modo il layout JSON viene documentato nel codice Rust.
Si prega di mostrare ciò che attualmente serializza a. –
@ker Non searializza nulla. Questo non è un codice valido. Perché "MyError" e "MyAge" non sono tipi compatibili. – user3384741
ooooh ... Hai provato a usare un enum? C'è un milione di modi per risolvere il tuo problema. Le soluzioni hanno diverse quantità e tipi di codice di cui hai bisogno per scrivere te stesso ... Sei vincolato a quel preciso formato di output? –