簡體   English   中英

通過實現 serde `Deserializer` 將值的 Vec 反序列化為結構

[英]Deserialize a Vec of values into a struct by implementing serde `Deserializer`

我有一個使用自定義枚舉值的數據格式。 我從數據庫收到一個Vec<MyVal> 我想將其轉換為結構(如果它不起作用則失敗)。 我想使用 serde,因為處理后我想將 API 響應作為 json 返回,而 serde 使這變得非常簡單。

該示例的游樂場鏈接

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

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

挑戰在於將數據格式轉換為 serde 數據 model。為此,我可以實現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>>作為 seq 訪問嗎?

前言:問題想要將 Rust 數據結構Vec<MyData>視為序列化數據(例如:像 JSON 字符串),並允許將其反序列化為任何其他實現Deserialize的 Rust 數據結構。 這是相當不尋常的,但並非沒有先例。 由於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反序列化MyValVecserde::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是包裝器結構一樣)。 特別是,如果您的最終目標是擁有 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)),
    ))
}

那么你完全不需要MyWrapper

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM