如何使用Serde反序列化带有来自读取器的引用的结构? [英] How do I use Serde to deserialize structs with references from a reader?
本文介绍了如何使用Serde反序列化带有来自读取器的引用的结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有这些结构:
#[derive(Debug, Serialize, Deserialize)]
pub struct GGConf<'a> {
#[serde(alias = "ssh")]
#[serde(rename = "ssh")]
#[serde(default)]
#[serde(borrow)]
pub ssh_config: Option<SSHConfig<'a>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SSHConfig<'a> {
#[serde(alias = "privateKey")]
#[serde(rename = "privateKey")]
private_key: &'a str,
username: &'a str,
}
读取YAML文件时发生反序列化:
let mut config: GGConf = serde_yaml::from_reader(file)?;
编译时,我收到错误:
error: implementation of `conf::_IMPL_DESERIALIZE_FOR_GGConf::_serde::Deserialize` is not general enough
--> src/conf.rs:50:34
|
50 | let mut config: GGConf = serde_yaml::from_reader(file)?;
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `conf::_IMPL_DESERIALIZE_FOR_GGConf::_serde::Deserialize` is not general enough
|
::: /home/ninan/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.98/src/de/mod.rs:524:1
|
524 | / pub trait Deserialize<'de>: Sized {
525 | | /// Deserialize this value from the given Serde deserializer.
526 | | ///
527 | | /// See the [Implementing `Deserialize`][impl-deserialize] section of the
... |
562 | | }
563 | | }
| |_- trait `conf::_IMPL_DESERIALIZE_FOR_GGConf::_serde::Deserialize` defined here
|
= note: `conf::GGConf<'_>` must implement `conf::_IMPL_DESERIALIZE_FOR_GGConf::_serde::Deserialize<'0>`, for any lifetime `'0`...
= note: ...but `conf::GGConf<'_>` actually implements `conf::_IMPL_DESERIALIZE_FOR_GGConf::_serde::Deserialize<'1>`, for some specific lifetime `'1`
我隐约知道serde反序列化也有生存期'de
,编译器会混淆我为它指定的生存期吗?如果我说错了,请纠正我。
当前如何正确地将YAML反序列化为这两个结构? 我是不是遗漏了什么或误解了什么?
我查看了How do I resolve "implementation of serde::Deserialize is not general enough" with actix-web's Json type?,但我不能使用拥有的类型。我需要它是借来的类型。
我将尝试为此编写一个操场示例。
推荐答案
这是不可能的;您必须使用拥有的数据而不是引用。
这里有一个最小的示例:
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
退出时被销毁,从而使引用无效。
另请参阅:
如果必须使用引用(在许多情况下并非如此),则需要:
- 自己从读取器读取到缓冲区
- 使用
from_str
而不是from_reader
- 保持缓冲区与反序列化数据一样长
这篇关于如何使用Serde反序列化带有来自读取器的引用的结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文