首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >通过实现serde ` Deserialize‘将值的Vec反序列化为结构

通过实现serde ` Deserialize‘将值的Vec反序列化为结构
EN

Stack Overflow用户
提问于 2022-02-24 03:30:57
回答 1查看 1.4K关注 0票数 2

我有一个使用自定义枚举值的数据格式。从数据库中,我接收到一个Vec<MyVal>。我想把它转换成一个结构(如果它不能工作,就会失败)。我想使用serde,因为经过处理后,我想以json的形式返回API响应,而serde使这非常容易。

示例的游乐场链接

代码语言:javascript
运行
复制
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可以使用的东西。这是一些示例代码。

代码语言:javascript
运行
复制
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())
    }
}

错误是

代码语言:javascript
运行
复制
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>>作为seq访问?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-24 13:37:11

前言:问题是要将锈蚀数据结构Vec<MyData>作为序列化的数据块(例如: JSON字符串),并允许将其反序列化为实现Deserialize的任何其他锈蚀数据结构。这是非常不寻常的,但也并非没有先例。而且,由于MyVal实际上是具有各种类型的数据片段,从数据库访问箱中返回,所以这种方法是有意义的。

这个问题中的代码的主要问题是它试图用一个单一的MyWrapper<Vec<MyVal>>反序列化两个不同的数据结构(MyValDeserializer )。显而易见的出路是定义第二个struct MyValWrapper(MyVal)并为其实现Deserializer

代码语言:javascript
运行
复制
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反序列化Vec of MyVals,serde::value::SeqDeserializer适配器非常方便,它可以将(Into)Deserializer的迭代器转换为序列Deserializer

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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是包装器结构一样)。特别是,如果你的最终目标是有一个功能,比如

代码语言:javascript
运行
复制
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了。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71246764

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档