[英]Deserialize a Vec of values into a struct by implementing serde `Deserializer`
I have a data format using custom enum of values.我有一个使用自定义枚举值的数据格式。 From the database I receive a Vec<MyVal>
.我从数据库收到一个Vec<MyVal>
。 I want to convert this to a struct (and fail if it doesn't work).我想将其转换为结构(如果它不起作用则失败)。 I want to use serde because after processing I want to return the API response as a json, and serde makes this super easy.我想使用 serde,因为处理后我想将 API 响应作为 json 返回,而 serde 使这变得非常简单。
Playground link for the example 该示例的游乐场链接
enum MyVal {
Bool(bool),
Text(String)
}
#[derive(Serialize, Deserialize)]
struct User {
name: String,
registered: bool
}
The challenge is with converting the data format into the serde data model. For this I can implement a Deserializer
and implement the visit_seq
method ie visit the Vec<MyVal>
as if it were a sequence and return the values one by one.挑战在于将数据格式转换为 serde 数据 model。为此,我可以实现Deserializer
并实现visit_seq
方法,即访问Vec<MyVal>
就好像它是一个序列并一个一个地返回值。 The visitor for User
can consume the visited values to build the struct User
. User
的访问者可以使用访问的值来构建struct User
。
However I'm not able to figure out how to convert the Vec
into something visitor_seq
can consume.但是我无法弄清楚如何将Vec
转换为visitor_seq
可以使用的东西。 Here's some sample code.这是一些示例代码。
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())
}
}
The error is错误是
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
So I looked into SeqAccess and it has an implementor that requires that whatever is passed to it implement the Iterator
trait.所以我研究了SeqAccess ,它有一个实现器,要求传递给它的任何东西都实现Iterator
特性。 But I thought I had that covered, because vec.into_iter
returns an IntoIter
, a consuming iterator which does implement the Iterator
trait.但我认为我已经涵盖了这一点,因为vec.into_iter
返回一个IntoIter
,一个确实实现Iterator
特性的消费迭代器。
So I'm completely lost as to what's going wrong here.所以我完全不知道这里出了什么问题。 Surely there must be a way to visit a Vec<Result<Value, Error>>
as a seq?当然必须有一种方法可以将Vec<Result<Value, Error>>
作为 seq 访问吗?
Preface: The question wants to treat a Rust data structure Vec<MyData>
like a serialized piece of data (eg: like a JSON string) and allow deserializing that into any other Rust data structure that implements Deserialize
.前言:问题想要将 Rust 数据结构Vec<MyData>
视为序列化数据(例如:像 JSON 字符串),并允许将其反序列化为任何其他实现Deserialize
的 Rust 数据结构。 This is a quite unusual, but not without precedent.这是相当不寻常的,但并非没有先例。 And since the MyVal
s are actually pieces of data with various types which get returned from a database access crate, this approach does make sense.由于MyVal
实际上是从数据库访问包返回的各种类型的数据片段,因此这种方法确实有意义。
The main problem with the code in the question is that it tries to deserialize two different data structures ( MyWrapper<Vec<MyVal>>
and MyVal
) with a single Deserializer
.问题中代码的主要问题是它试图使用单个Deserializer
序列化两个不同的数据结构( MyWrapper<Vec<MyVal>>
和MyVal
)。 The obvious way out is to define a second struct MyValWrapper(MyVal)
and implement Deserializer
for it:显而易见的出路是定义第二个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
now can deserialize a MyVal
. MyValWrapper
现在可以反序列MyVal
。 To use MyValWrapper
to deserialize a Vec
of MyVal
s, the serde::value::SeqDeserializer
adapter is convenient, it can turn an iterator of ( Into
) Deserializer
into a sequence Deserializer
:要使用MyValWrapper
反序列化MyVal
的Vec
, 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)
For some reason, SeqDeserializer
requires the iterator items to be IntoDeserializer
, but no impl<T: IntoDeserializer> Deserializer for T
exists, so we need to make sure that MyValWrapper
is not only a Deserializer
but trivially also an IntoDeserializer
:出于某种原因, 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
}
}
Finally, you need to impl Deserializer for MyWrapper
(you can use the "Vec deserialization snippet" for that) — if you do actually need Deserializer
to be implemented, which I suspect you don't: the SeqDeserializer
already implements Deserializer
, and it is a wrapper struct (just as MyWrapper
is a wrapper struct).最后,你需要impl Deserializer for MyWrapper
(你可以为此使用“Vec 反序列化片段”)——如果你确实需要实现Deserializer
,我怀疑你不需要: SeqDeserializer
已经实现了Deserializer
,它是包装器结构(就像MyWrapper
是包装器结构一样)。 Especially, if your final goal is having a function like特别是,如果您的最终目标是拥有 function 之类的
fn turn_bad_myvals_into_good_T<T: DeserializeOwned>(v: Vec<MyVal>) -> T {
T::deserialize(SeqDeserializer::new(
v.into_iter().map(|myval| MyValWrapper(myval)),
))
}
then you entirely don't need MyWrapper
.那么你完全不需要MyWrapper
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.