且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用Serde反序列化带有来自读取器的引用的结构?

更新时间:2022-12-19 12:31:30

这是不可能的;您必须使用拥有的数据而不是引用。

这里有一个最小的示例:

use serde::Deserialize; // 1.0.104

#[derive(Debug, Deserialize)]
pub struct SshConfig<'a> {
    username: &'a str,
}

fn example(file: impl std::io::Read) {
    serde_yaml::from_reader::<_, SshConfig>(file);
}
error: implementation of `_IMPL_DESERIALIZE_FOR_SshConfig::_serde::Deserialize` is not general enough
   --> src/lib.rs:9:5
    |
9   |       serde_yaml::from_reader::<_, SshConfig>(file);
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `_IMPL_DESERIALIZE_FOR_SshConfig::_serde::Deserialize` is not general enough
    | 
   ::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.104/src/de/mod.rs:531:1
    |
531 | / pub trait Deserialize<'de>: Sized {
532 | |     /// Deserialize this value from the given Serde deserializer.
533 | |     ///
534 | |     /// See the [Implementing `Deserialize`][impl-deserialize] section of the
...   |
569 | |     }
570 | | }
    | |_- trait `_IMPL_DESERIALIZE_FOR_SshConfig::_serde::Deserialize` defined here
    |
    = note: `SshConfig<'_>` must implement `_IMPL_DESERIALIZE_FOR_SshConfig::_serde::Deserialize<'0>`, for any lifetime `'0`...
    = note: ...but `SshConfig<'_>` actually implements `_IMPL_DESERIALIZE_FOR_SshConfig::_serde::Deserialize<'1>`, for some specific lifetime `'1`

如果您查看serde_yaml::from_reader的定义,您会发现它仅限于反序列化所拥有的数据:

pub fn from_reader<R, T>(rdr: R) -> Result<T>
where
    R: Read,
    T: DeserializeOwned,
//     ^^^^^^^^^^^^^^^^ 

serde_json::from_reader和可能任何等效函数都是如此。

只有在有要引用的数据时才能反序列化包含引用的类型。实现Read特征的东西只能保证它可以将一些字节复制到用户提供的缓冲区中。由于from_reader函数不接受该缓冲区作为参数,因此任何缓冲区都将在from_reader退出时被销毁,从而使引用无效。

另请参阅:


如果必须使用引用(在许多情况下并非如此),则需要:

  1. 自己从读取器读取到缓冲区
  2. 使用from_str而不是from_reader
  3. 保持缓冲区与反序列化数据一样长