自定义数据格式 - `Deserializer::deserialize_str` 实现

Custom data format - `Deserializer::deserialize_str` implementation

Link 去游乐场

我正在尝试使用 serde 实现自定义数据格式,我一直在努力使用 deserialize_str 方法

pub struct Deserializer<R> {
    rdr: R,
}

impl<'de, 'a, R: io::Read + 'de> de::Deserializer<'de> for &'a mut Deserializer<R> {
    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
    where
        V: Visitor<'de>,
    {
        let len = self.read_i16()?; // implemention below
        if len == 0 || len == -1 {
            return visitor.visit_borrowed_str("");
        }
        let len = len as usize;
        let buf = self.read_exact(len)?; // implemention below
        let out_str = std::str::from_utf8(&buf)?;

        // visitor.visit_borrowed_str(out_str) doesn't compile
        visitor.visit_str(out_str) // compiles but errors
    }
}

impl<R: io::Read> Deserializer<R> {
    fn read_exact(&mut self, len: usize) -> Result<Vec<u8>> {
        let mut buf = vec![0; len];
        self.rdr.read_exact(&mut buf)?;
        Ok(buf)
    }

    fn read_i16(&mut self) -> io::Result<i8> {
        self.rdr.read_i16::<byteorder::NetworkEndian>()
    }
}


使用visitor.visit_borrowed_str(out_str)时,出现错误

    |
94  | impl<'de, 'a, R: io::Read + 'de> de::Deserializer<'de> for &'a mut Deserializer<R> {
    |      --- lifetime `'de` defined here
...
149 |         let out_str = std::str::from_utf8(&buf)?;
    |                                           ^^^^ borrowed value does not live long enough
150 |
151 |         visitor.visit_borrowed_str(out_str)
    |         ----------------------------------- argument requires that `buf` is borrowed for `'de`
152 |     }
    |     - `buf` dropped here while still borrowed

我知道 out_str 需要以某种方式比它的范围更长寿,但我找不到解决它的方法。

要使用 visit_borrowed_str,您需要向它传递一个与您的反序列化器一样长寿的东西的引用。使用 read_exact 创建一个新的临时 Vec 是行不通的,您需要访问底层切片,例如std::str::from_utf8(self.rdr.get_ref()[self.rdr.position()..][..len]) 或类似的。如果你想让 R 保持通用 std::io::Read,我认为你不能使用 visit_borrowed_strserde_json 例如通过有一个特殊的 Read 来处理这个问题,returns 对基础数据的引用 if it can, and then only uses visit_borrowed_str if it does have a reference 对基础数据的引用。

此外,如果您要求反序列化器反序列化为借用的字符串,而它不能反序列化,则它必然会出错。 holds true 也适用于 serde_json。所以来自 visit_str 的错误不是你的反序列化器实现中的错误,而是你如何使用反序列化器的错误。您应该要求反序列化为 StringCow<str>(并不是说您的序列化程序可以给您 Cow::Borrowed,但要求 &str 并不是对于任何解串器来说都是个好主意,通常建议使用 Cow<str>