通过实现 serde `Deserializer` 将值的 Vec 反序列化为结构
Deserialize a Vec of values into a struct by implementing serde `Deserializer`
我有一个使用自定义值枚举的数据格式。我从数据库收到一个 Vec<MyVal>
。我想将其转换为结构(如果它不起作用则失败)。我想使用 serde,因为在处理后我想 return API 响应作为 json,而 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>
就好像它是一个序列和 return 一个一个地访问值。 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
return 是一个 IntoIter
,一个确实实现了 Iterator
特性的消费迭代器。
所以我完全不知道这里出了什么问题。肯定有办法将 Vec<Result<Value, Error>>
作为 seq 访问吗?
前言:问题想要将 Rust 数据结构 Vec<MyData>
视为序列化数据(例如:像 JSON 字符串)并允许将其反序列化为任何其他 Rust 数据结构实施 Deserialize
。这是相当不寻常的,但并非没有先例。由于 MyVal
实际上是从数据库访问箱返回的各种类型的数据片段,因此这种方法确实有意义。
问题中代码的主要问题是它试图用单个 Deserializer
反序列化两种不同的数据结构(MyWrapper<Vec<MyVal>>
和 MyVal
)。显而易见的出路是定义第二个 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
反序列化一个MyVal
的Vec
,serde::value::SeqDeserializer
适配器很方便,它可以转一个(Into
)[=19=的迭代器] 成序列 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
.
我有一个使用自定义值枚举的数据格式。我从数据库收到一个 Vec<MyVal>
。我想将其转换为结构(如果它不起作用则失败)。我想使用 serde,因为在处理后我想 return API 响应作为 json,而 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>
就好像它是一个序列和 return 一个一个地访问值。 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
return 是一个 IntoIter
,一个确实实现了 Iterator
特性的消费迭代器。
所以我完全不知道这里出了什么问题。肯定有办法将 Vec<Result<Value, Error>>
作为 seq 访问吗?
前言:问题想要将 Rust 数据结构 Vec<MyData>
视为序列化数据(例如:像 JSON 字符串)并允许将其反序列化为任何其他 Rust 数据结构实施 Deserialize
。这是相当不寻常的,但并非没有先例。由于 MyVal
实际上是从数据库访问箱返回的各种类型的数据片段,因此这种方法确实有意义。
问题中代码的主要问题是它试图用单个 Deserializer
反序列化两种不同的数据结构(MyWrapper<Vec<MyVal>>
和 MyVal
)。显而易见的出路是定义第二个 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
反序列化一个MyVal
的Vec
,serde::value::SeqDeserializer
适配器很方便,它可以转一个(Into
)[=19=的迭代器] 成序列 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
.