2016-06-01 21 views
5

Voglio creare un array con i messaggi di errore e gli oggetti appropriati.Matrice JSON ruggine con oggetti/errori diversi?

#[derive(Serialize, Deserialize, Debug)] 
pub struct MyError { 
    error: String 
} 

#[derive(Serialize, Deserialize, Debug)] 
pub struct MyAge { 
    age: i32, 
    name: String 
} 

fn get_results(ages: Vec<i32>) -> Vec<MyAge> { 
    let mut results = vec![]; 
    for age in ages { 
     if age < 100 && age > 0 { 
      results.push(MyAge{age: age, name: String::from("The dude")}); 
     } else { 
      results.push(MyError{error: String::from(format!("{} is invalid age", age)) }); 
     } 
    } 
    results 
} 

Uso Serde per serializzare il JSON. Quando passo in Vec [1,-6,7] voglio un array che serializza nel serde al JSON:

[{"age": 1, "name": "The dude"},{"error": "-6 is invalid age"},{"age": 7, "name": "The dude"}] 

Come posso fare? Sapere come deserializzare un array di questo tipo sarebbe anche bello.

+1

Si prega di mostrare ciò che attualmente serializza a. –

+0

@ker Non searializza nulla. Questo non è un codice valido. Perché "MyError" e "MyAge" non sono tipi compatibili. – user3384741

+1

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? –

risposta

8

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.

5

Serde supporta enum etichettati e senza tag interni dalla versione 0.9.6.

Il seguente codice mostra un esempio di come ciò potrebbe essere eseguito utilizzando un enum con l'attributo #[serde(untagged)].

#[macro_use] 
extern crate serde_derive; 

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(Serialize, Deserialize, Debug)] 
#[serde(untagged)] 
pub enum AgeOrError { 
    Age(MyAge), 
    Error(MyError), 
} 

fn get_results(ages: Vec<i32>) -> Vec<AgeOrError> { 
    let mut results = Vec::with_capacity(ages.len()); 
    for age in ages { 
     if age < 100 && age > 0 { 
      results.push(AgeOrError::Age(MyAge { 
       age: age, 
       name: String::from("The dude") 
      })); 
     } else { 
      results.push(AgeOrError::Error(MyError { 
       error: String::from(format!("{} is invalid age", age)) 
      })); 
     } 
    } 
    results 
} 

fn main() { 
    let results = get_results(vec![1, -6, 7]); 
    let json = serde_json::to_string(&results).unwrap(); 
    println!("{}", json); 
} 

Il codice precedente restituisce il seguente JSON:

[{"age":1,"name":"The dude"},{"error":"-6 is invalid age"},{"age":7,"name":"The dude"}] 

Ulteriori informazioni sulla rappresentanza enumerazione di Serde si trovano nella overview.

Problemi correlati