serialization - 通过实现 serde `Deserializer` 将值的 Vec 反序列化为结构体

标签 serialization rust serde

我有一个使用自定义值枚举的数据格式。我从数据库收到 Vec<MyVal> 。我想将其转换为结构(如果不起作用则失败)。我想使用 serde,因为处理后我想以 json 形式返回 API 响应,而 serde 使这变得非常简单。

Playground link for the example

enum MyVal {
  Bool(bool),
  Text(String)
}

#[derive(Serialize, Deserialize)]
struct User {
  name: String,
  registered: bool
}

挑战在于将数据格式转换为 serde 数据模型。为此我可以实现 Deserializer并实现visit_seq方法即访问 Vec<MyVal>就好像它是一个序列并一一返回值。 User的访客可以使用访问过的值来构建 struct User .

但是我无法弄清楚如何转换 Vec进入某事visitor_seq可以消费。这是一些示例代码。

struct MyWrapper(Vec<MyVal>);

impl<'de> Deserializer<'de> for MyWrapper {
    type Error = de::value::Error;

    // skip unncessary

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let convert_myval = move |myval: &MyVal| match myval {
            MyVal::Bool(b) => visitor.visit_bool(*b),
            MyVal::Text(s) => visitor.visit_string(s.clone())
        };

        // now I have a vec of serde values
        let rec_vec: Vec<Result<V::Value, Self::Error>> =
            self.0.iter().map(|myval| convert_myval(myval)).collect();
        // giving error!!
        visitor.visit_seq(rec_vec.into_iter())
    }
}

错误是

92   |         visitor.visit_seq(rec_vec.into_iter())
     |                 --------- ^^^^^^^^^^^^^^^^^^^ the trait `SeqAccess<'de>` is not implemented for `std::vec::IntoIter<Result<<V as Visitor<'de>>::Value, _::_serde::de::value::Error>>`
     |                 |
     |                 required by a bound introduced by this call

所以我调查了 SeqAccess它有一个实现者,要求传递给它的任何内容都实现 Iterator特征。但我认为我已经涵盖了这一点,因为 vec.into_iter返回 IntoIter ,一个消费迭代器,它实现了 Iterator特质。

所以我完全不知道这里出了什么问题。肯定有办法访问 Vec<Result<Value, Error>>作为一个序列?

最佳答案

前言:问题想要处理 Rust 数据结构 Vec<MyData>像序列化的数据片段(例如:像 JSON 字符串),并允许将其反序列化到任何其他实现 Deserialize 的 Rust 数据结构中。这是一个相当不寻常的事件,但并非没有先例。自从 MyVal实际上是从数据库访问包返回的各种类型的数据,这种方法确实有意义。

问题中代码的主要问题是它尝试使用单个 MyWrapper<Vec<MyVal>> 反序列化两个不同的数据结构( MyValDeserializer )。 。明显的出路是定义第二个 struct MyValWrapper(MyVal)并实现Deserializer对于它:

struct MyValWrapper(MyVal);
impl<'de> Deserializer<'de> for MyValWrapper {
    type Error = de::value::Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.0 {
            MyVal::Bool(b) => visitor.visit_bool(b),
            MyVal::Text(s) => visitor.visit_string(s.clone()),
        }
    }

    // Maybe you should call deserialize_any from all other deserialize_* functions to get a passable error message, e.g.:
    forward_to_deserialize_any! {
        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
        bytes byte_buf option unit unit_struct newtype_struct seq tuple
        tuple_struct map struct enum identifier ignored_any
    }
    // Though maybe you want to handle deserialize_enum differently...
}

MyValWrapper现在可以反序列化 MyVal 。使用MyValWrapper反序列化 VecMyVal s,serde::value::SeqDeserializer适配器很方便,它可以转一个 ( Into ) Deserializer 的迭代器进入序列Deserializer :

let data: Vec<MyData> = …;
// Vec deserialization snippet
let mut sd = SeqDeserializer::new(data.into_iter().map(|myval| MyValWrapper(myval)));
let res = visitor.visit_seq(&mut sd)?;
sd.end()?;
Ok(res)

由于某种原因,SeqDeserializer要求迭代器项为 IntoDeserializer ,但没有impl<T: IntoDeserializer> Deserializer for T存在,所以我们需要确保MyValWrapper不仅仅是Deserializer但也很简单 IntoDeserializer :

impl<'de> IntoDeserializer<'de> for MyValWrapper {
    type Deserializer = MyValWrapper;
    fn into_deserializer(self) -> Self::Deserializer {
        self
    }
}

最后,您需要 impl Deserializer for MyWrapper (您可以使用“Vec 反序列化片段”)——如果您确实需要 Deserializer要实现,我怀疑你没有: SeqDeserializer已经实现 Deserializer ,并且它是一个包装结构(就像 MyWrapper 是一个包装结构)。特别是,如果您的最终目标是拥有类似的功能

fn turn_bad_myvals_into_good_T<T: DeserializeOwned>(v: Vec<MyVal>) -> T {
    T::deserialize(SeqDeserializer::new(
        v.into_iter().map(|myval| MyValWrapper(myval)),
    ))
}

那么你完全不需要MyWrapper .

关于serialization - 通过实现 serde `Deserializer` 将值的 Vec 反序列化为结构体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71246764/

相关文章:

java - jackson - 具有受控精度的 double json 编码

json - JSON响应的反序列化在字符串中保留引号

rust - 如何使用 serde 序列化选项?

rust - 为什么没有为明确实现的类型实现特征?

python - 保存和加载 scikit-learn 机器学习模型和函数

c# - 重复序列化和反序列化创建重复项

c# - 如何从派生类中只获取基类属性?

rust - 为什么在 .split() 之后我得到一个空的 &str?

r - 在 R 中加载链接到 Rust 库的共享库

rust - 为什么带有子模块和名称冲突的函数的模块可以工作?