【问题标题】:How to implement serde::Deserialize on struct containing &'static str?如何在包含 &'static str 的结构上实现 serde::Deserialize?
【发布时间】:2021-05-22 13:42:43
【问题描述】:

我正在尝试在SourceConfig 结构上实现serde::Deserialize,它包装了一个包含&'static str 的结构以及它自己的一些数据(playground)

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Config {
    pub name: &'static str,
}

#[derive(Serialize, Deserialize)]
struct SourceConfig {
    config: Config,
    id: u32,
}

但这给了我一生的错误:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements
  --> src/lib.rs:10:5
   |
10 |     config: Config,
   |     ^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'de` as defined on the impl at 8:21...
  --> src/lib.rs:8:21
   |
8  | #[derive(Serialize, Deserialize)]
   |                     ^^^^^^^^^^^
note: ...so that the types are compatible
  --> src/lib.rs:10:5
   |
10 |     config: Config,
   |     ^^^^^^
   = note: expected `SeqAccess<'_>`
              found `SeqAccess<'de>`
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the types are compatible
  --> src/lib.rs:10:5
   |
10 |     config: Config,
   |     ^^^^^^
   = note: expected `Deserialize<'_>`
              found `Deserialize<'static>`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements
  --> src/lib.rs:10:5
   |
10 |     config: Config,
   |     ^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'de` as defined on the impl at 8:21...
  --> src/lib.rs:8:21
   |
8  | #[derive(Serialize, Deserialize)]
   |                     ^^^^^^^^^^^
note: ...so that the types are compatible
  --> src/lib.rs:10:5
   |
10 |     config: Config,
   |     ^^^^^^
   = note: expected `MapAccess<'_>`
              found `MapAccess<'de>`
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the types are compatible
  --> src/lib.rs:10:5
   |
10 |     config: Config,
   |     ^^^^^^
   = note: expected `Deserialize<'_>`
              found `Deserialize<'static>`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors

我尝试将#[serde(borrow)] 添加到SourceConfig 中的config,但这不起作用,因为Config 没有被借用。将其添加到Config 中的name 也不起作用。如何在SourceConfig 上正确实现Deserialize

【问题讨论】:

    标签: string rust deserialization borrow-checker serde


    【解决方案1】:

    您可以在SourceConfig 结构上添加bound,这样'de 的生命周期就等于'static 的生命周期。

    #[derive(Debug, serde::Deserialize)]
    pub struct Config {
        pub name: &'static str,
    }
    
    #[derive(Debug, serde::Deserialize)]
    #[serde(bound(deserialize = "'de: 'static"))]
    struct SourceConfig {
        config: Config,
        id: u32,
    }
    
    fn main() {
        let j = r#"
    {
        "id": 123,
        "config": {
            "name": "John Smith"
        }
    }
        "#;
        
        let sc: SourceConfig = serde_json::from_str(&j).unwrap();
        dbg!(sc);
    }
    

    但是,您可能不想反序列化 &amp;'static str,因为这需要您有一个 &amp;'static str 可以借用。这将您限制为字符串文字,或者您需要泄漏内存来获取&amp;'static str。 您可能需要String,或者,如果您想支持字符串文字,则需要Cow&lt;'a, str&gt;

    &amp;'a str 的另一个问题是,如果使用转义序列对字符串进行序列化,它将无法工作。例如,包含换行符的 JSON 字符串将具有 \n,在反序列化期间需要替换它,因此如果您使用 &amp;'a str,则会失败。

    【讨论】:

    • 很好的答案。谢谢。我可以让它以相反的方式工作:#[serde(bound(deserialize = "'static: 'de"))]
    • 我没想到\n 案子!当 JSON 中有 \n 之类的内容时,serde_json 给出的错误如下:Error("invalid type: string \"John\\nSmith\", expected a borrowed string", line: 5, column: 29)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-03
    • 2019-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    相关资源
    最近更新 更多