2016-06-01 4 views
5

오류 메시지와 적절한 개체가 포함 된 배열을 만들고 싶습니다.다른 개체/오류가있는 녹슨 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을 직렬화합니다. 내가 그렇게 어떻게

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

: 나는 VEC [1,-6,7]에 전달하면 내가 JSON에 serde에 직렬화 배열을 원하는? 그런 배열을 deserialize하는 방법을 아는 것도 좋을 것입니다.

+1

현재 일련 번호를 표시하십시오. –

+0

@ker 그것은 무엇이든 검색하지 않습니다. 이것은 유효한 코드가 아닙니다. "MyError"및 "MyAge"는 호환 유형이 아니기 때문에 – user3384741

+1

우 ... 대신 enum을 사용해 보셨나요? 문제를 해결하는 데는 백만 가지 방법이 있습니다. 솔루션에는 직접 작성해야하는 코드와 양이 있습니다. 정확한 출력 형식에 구속되어 있습니까? –

답변

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

주 이유는
가) 직렬화 종류의 우리에게 필드를 스트리밍, 우리 peook을 문자열로 묶은 JSON 표현으로 변환 할 수 없으며 그것이 무엇인지 추측 할 수 없습니다.
b) Serde가 생성하는 serde::de::Visitor 구현에 액세스 할 수 없습니다.

또한 바로 가기와 panick 오류가 발생했습니다. 프로덕션 코드에서는 적절한 Serde 오류를 반환하는 것이 좋습니다.


또 다른 해결책은 다음과 같이 선택 모든 필드와 병합 된 구조를 확인하는 것입니다 :

#[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 버전부터 내부적으로 태그 지정 및 태그 해제 된 enum을 지원합니다.

다음 코드는 #[serde(untagged)] 특성을 가진 열거 형을 사용하여이 작업을 수행 할 수있는 방법의 예를 보여줍니다.

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

Serde ENUM의 표현에 대한 추가 정보가 overview에서 찾을 수있다 :

#[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 출력한다.