Nun, hier ist ein Weg, dies zu tun:
#[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);
}
Beachten Sie, dass in der Deserialisierung können wir nicht die automatisch generierten Deserializer wiederverwenden, weil:
a) Deserialisierung Art streamt die Felder zu uns, wir kann nicht peek in die stringifizierte JSON-Darstellung und raten Sie, was es ist;
b) Wir haben keinen Zugriff auf die serde::de::Visitor
Implementierungen, die Serde generiert.
Auch ich habe eine Abkürzung und panick
Ed auf Fehler. Im Produktionscode möchten Sie stattdessen die richtigen Serde-Fehler zurückgeben.
Eine andere Lösung wäre, eine fusionierte Struktur mit allen Feldern wie diese optional zu machen:
#[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);
}
ich für diese bürgen würde, weil es die Struktur Rust ermöglicht (zB) übereinstimmen das Layout Ihres JSON. Auf diese Weise wird das JSON-Layout im Rust-Code dokumentiert.
Bitte zeigen Sie, was es derzeit serialisiert. –
@ker Es wird nicht zu etwas searialisieren. Dies ist kein gültiger Code. Weil "MyError" und "MyAge" nicht kompatible Typen sind. – user3384741
oooh ... Hast du es stattdessen mit einem Enum versucht? Es gibt eine Million Möglichkeiten, um Ihr Problem zu lösen. Die Lösungen haben unterschiedliche Mengen und Arten von Code, die Sie selbst schreiben müssen ... Sind Sie an das genaue Ausgabeformat gebunden? –