rust - 如何使用 Serde 反序列化带有读者引用的结构?

标签 rust yaml deserialization lifetime 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 退出时被破坏,从而使引用无效。

也可以看看:
  • How do I resolve "implementation of serde::Deserialize is not general enough" with actix-web's Json type?


  • 如果您 必须 使用引用(在许多情况下这不是真的),您将需要:
  • 自己从读取器读取到缓冲区
  • 使用 from_str 而不是 from_reader
  • 只要反序列化数据就保持缓冲区
  • 关于rust - 如何使用 Serde 反序列化带有读者引用的结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60801133/

    相关文章:

    rust - 如何将 float 格式化为第一位有效小数并具有指定的精度

    azure - 如何将环境特定值传递给Azure管道?

    时间:2019-03-27 标签:c#NewtonJsonJarraychecknull/empty错误

    rust - 如何确保在函数调用后结束不可变借用以启用可变借用?

    rust - 从 MPSC channel 成功接收后进程永不退出

    caching - 在不是结构方法的函数上实现缓存的惯用方法是什么?

    java - 让 Jackson 对输入 JSON 更友好

    当我们在资源部分下的kustomization.yaml文件中指定基本 list 文件时,Kubernetes kustomize命令给出错误

    bash - 从 YAML 模板更新变量的值

    c# - 为什么当我使用 JSON.NET 反序列化时会忽略我的默认值?