2016-06-01 2 views
5

Я хочу создать массив с сообщениями об ошибках, а также с соответствующими объектами.Rust serde JSON массив с различными объектами/ошибками?

#[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 
} 

Я использую serde для сериализации JSON. Когда я прохожу в Vec [1,-6,7] Я хочу, чтобы массив, который сериализующий в serde в формате JSON:

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

Как сделать это? Знать, как десериализовать такой массив, было бы неплохо.

+1

, пожалуйста, покажите, к чему это приведет. –

+0

@ker Он не искажает ничего. Это недопустимый код. Поскольку «MyError» и «MyAge» не являются совместимыми типами. – user3384741

+1

ooooh ... Вы пробовали использовать перемычку? Есть миллион способов решить вашу проблему. Решения имеют разные количества и типы кода, которые вам нужно написать сами ... Вы связаны с этим точным форматом вывода? –

ответ

8

Ну, вот один из способов сделать это:

#[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); 
} 

Обратите внимание, что в десериализации мы не можем повторно использовать автоматически сгенерированные deserializers, потому что:
а) десериализации является своего рода потокового поля к нам, не может peek в строковое представление JSON и догадываться, что это такое;
b) у нас нет доступа к реализациям serde::de::Visitor, которые генерирует Serde.

Также я сделал ярлык и panick ed об ошибках. В производственном коде вы хотели бы вернуть правильные ошибки Серда.


Другим решением было бы сделать объединенную структуру со всеми полями необязательных, как это:

#[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); 
} 

Я ручаюсь за это, потому что она позволяет структуру ржавчины (например), чтобы соответствовать расположение вашего JSON. Таким образом, компоновка JSON документируется в коде Rust.

5

Serde поддерживает внутренне помеченные и немаркированные перечисления с версии 0.9.6.

В следующем примере показан пример того, как это можно сделать, используя перечисление с атрибутом #[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); 
} 

Приведенный выше код выдает следующий JSON:

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

Более подробная информация о представлении перечислений Serde можно найти в overview.

Смежные вопросы