如何将 Serde 与具有不同对象的 JSON 数组一起使用以获取成功和错误? [英] How can I use Serde with a JSON array with different objects for successes and errors?

查看:15
本文介绍了如何将 Serde 与具有不同对象的 JSON 数组一起使用以获取成功和错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用 Serde 创建一个包含错误消息和正确对象的数组:

I want to use Serde to create an array with error messages as well as proper objects:

extern crate serde; // 1.0.70
#[macro_use]
extern crate serde_derive; // 1.0.70
extern crate serde_json; // 1.0.24

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

当我传入 Vec [1, -6, 7] 我想序列化到 JSON:

When I pass in the Vec [1, -6, 7] I want to serialize to the JSON:

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

我该怎么做?知道如何反序列化这样的数组也会很好.

How do I do that? Knowing how to deserialize such an array would be nice as well.

推荐答案

这是一种方法:

#[macro_use]
extern crate serde_derive; // 1.0.117
extern crate serde; // 1.0.117
extern crate serde_json; // 1.0.59

#[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<'de> serde::Deserialize<'de> for AgeOrErrorField {
    fn deserialize<D>(deserializer: D) -> Result<AgeOrErrorField, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct AgeOrErrorFieldVisitor;

        impl<'de> serde::de::Visitor<'de> 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_any(AgeOrErrorFieldVisitor)
    }
}

impl<'de> serde::Deserialize<'de> for AgeOrError {
    fn deserialize<D>(deserializer: D) -> Result<AgeOrError, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_map(AgeOrErrorVisitor)
    }
}

struct AgeOrErrorVisitor;

impl<'de> serde::de::Visitor<'de> for AgeOrErrorVisitor {
    type Value = AgeOrError;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(formatter, "age or error")
    }

    fn visit_map<A>(self, mut map: A) -> Result<AgeOrError, A::Error>
    where
        A: serde::de::MapAccess<'de>,
    {
        let mut age: Option<i32> = None;
        let mut name: Option<String> = None;
        let mut error: Option<String> = None;
        loop {
            match map.next_key()? {
                Some(AgeOrErrorField::Age) => age = map.next_value()?,
                Some(AgeOrErrorField::Name) => name = map.next_value()?,
                Some(AgeOrErrorField::Error) => error = map.next_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
}

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

请注意,在反序列化中我们不能重用自动生成的反序列化器,因为:

Note that in deserialization we can't reuse the automatically generated deserializers because:

  1. 反序列化是将字段流式传输给我们,我们无法窥视字符串化的 JSON 表示并猜测它是什么;
  2. 我们无权访问 Serde 生成的 serde::de::Visitor 实现.
  1. deserialization is kind of streaming the fields to us, we can't peek into the stringified JSON representation and guess what it is;
  2. we don't have access to the serde::de::Visitor implementations that Serde generates.

我还做了一个快捷方式,并panic对错误进行了处理.在生产代码中,您希望返回正确的 Serde 错误.

Also I did a shortcut and panicked on errors. In production code you'd want to return the proper Serde errors instead.

另一种解决方案是创建一个包含所有可选字段的合并结构,如下所示:

Another solution would be to make a merged structure with all fields optional, like this:

#[macro_use]
extern crate serde_derive; // 1.0.70
extern crate serde; // 1.0.70
extern crate serde_json; // 1.0.24

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

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

我保证这个是因为它允许 Rust 结构(例如 MyAgeOrError)与您的 JSON 布局相匹配.这样 JSON 布局就会记录在 Rust 代码中.

I'd vouch for this one because it allows the Rust structure (e.g. MyAgeOrError) to match the layout of your JSON. That way the JSON layout becomes documented in the Rust code.

附言最近,我倾向于在 的帮助下延迟对可选或动态类型 JSON 部分的解码原始值.但是序列化它们很棘手,因为 RawValue 是借用的.例如,为了帮助序列化,可以实习一个 RawValue,将其提升到 'static 生命周期:

P.S. Lately I tend to delay the decoding of optional or dynamically typed JSON parts with the help of RawValue. It's tricky to serialize them though, because RawValue is a borrow. For instance, and to help with serialization, one can intern a RawValue, promoting it to the 'static lifetime:

use serde_json::value::{RawValue as RawJson};

fn intern_raw_json(raw_json: Box<RawJson>) -> &'static RawJson {
    use parking_lot::Mutex;
    use std::mem::transmute;

    static BUF: Mutex<Vec<Pin<Box<RawJson>>>> = Mutex::new(Vec::new());

    let buf = BUF.lock();
    let raw_json: Pin<Box<RawJson>> = raw_json.into();
    let pt: &'static RawJson = {
        let pt: &RawJson = &*raw_json;
        transmute(pt)
    };
    buf.push(raw_json);
    pt
}

如果性能不是问题,那么可以将动态部分反序列化为 Value.
同样,如果使用 Value 是一个选项,那么自定义反序列化可以通过实现 TryFrom.

If performance is not an issue, then one can deserialize the dynamic parts into the Value.
Similarly, if using Value is an option, then custom deserialization can be simplified by implementing TryFrom<Value>.

这篇关于如何将 Serde 与具有不同对象的 JSON 数组一起使用以获取成功和错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆