【问题标题】:serde_json with deserialize and lifetimes for generic function具有反序列化和通用函数生命周期的 serde_json
【发布时间】:2021-08-15 20:17:04
【问题描述】:

生命周期和 serde::deserialize 存在问题。 尝试阅读错误消息并尝试实现反序列化,但随后出现错误,我需要实现反序列化。
没有生命周期,它可以工作

use serde::{ Deserialize, Serialize, de::DeserializeOwned};
use std::error::Error;
use std::io::{BufReader};
use std::{ fmt::Debug};
use std::{fs::File};

#[derive(Clone, Debug, Serialize, Deserialize)]
struct User<'a> {
    name: &'a str,
}

fn main(){
    let b: User = read_object("user_1.json").unwrap();
}


fn read_object<T>(path: &str) -> Result<T, Box<dyn Error>>
where
    T: DeserializeOwned + Debug,
{
    let f = File::open(&path)?;
    let reader = BufReader::new(f);

    let t: T = serde_json::from_reader(reader)?;

    Ok(t)
}

错误:

   error: implementation of `Deserialize` is not general enough
  --> src/main.rs:13:19
   |
13 |     let b: User = read_object("user_1.json").unwrap();
   |                   ^^^^^^^^^^^ implementation of `Deserialize` is not general enough
   |
   = note: `User<'_>` must implement `Deserialize<'0>`, for any lifetime `'0`...
   = note: ...but `User<'_>` actually implements `Deserialize<'1>`, for some specific lifetime `'1`

【问题讨论】:

    标签: rust


    【解决方案1】:

    此代码无法运行。

    Deserialize&lt;'de&gt; 特征具有与之关联的生命周期,以支持零拷贝反序列化。本质上允许反序列化类型直接从源引用数据。见Understanding deserializer lifetimes

    当你有

    #[derive(Deserialize)]
    struct User<'a> {
        name: &'a str,
    }
    

    User 的生命周期 'a 将链接到反序列化源。而name 将是对该源中字符串值的引用。

    另一方面,DeserializeOwned trait 不支持零拷贝反序列化。反序列化类型不得具有与Deserializer 关联的生命周期。 “拥有”意味着它不借任何东西。您得到的神秘错误是由于 DeserializeOwned 的定义方式,它将为在 any 生命周期内实现 Deserialize 的任何类型实现,这将排除期望特定生命周期的类型。当生命周期不需要或无法保证时使用此界限。

    serde_json::from_reader 就是其中一种情况。它仅从基于 Read 特征的源中反序列化 JSON。但是,Read 特征不保证任何读取的数据在事后都是可引用的。因此from_reader 指示T: DeserializeOwned 避免该问题。

    要利用零拷贝反序列化,您需要使用 from_slicefrom_str

    let data = std::fs::read_to_string(path)?;
    let user: User = serde_json::from_str(&data)?;
    

    但是,即使您这样做,所引用的数据也仅对 read_object 函数是本地的。从文件中检索到的所有数据都在函数结束时被销毁,如果返回,user.name 将无效。编译器会拒绝它 (playground)。

    没有生命周期,它可以工作

    这就是我建议你做的;只需使用struct User { name: String }。由于escape sequences,我建议不要尝试从 JSON 字符串中使用零成本反序列化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-05
      • 2018-01-28
      • 2014-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多