serde_json 具有反序列化和通用函数的生命周期

end*_*maz 4 rust

存在生命周期和 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)
}
Run Code Online (Sandbox Code Playgroud)

错误:

   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`
Run Code Online (Sandbox Code Playgroud)

kmd*_*eko 9

This code cannot work.

The Deserialize<'de> trait has a lifetime associated with it to support zero-copy deserialization. Essentially allows deserialized types to reference data directly from the source. See Understanding deserializer lifetimes.

When you have

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

The User will have the lifetime 'a linked to the deserialization source. And name will be a reference to the string value within that source.

On the flip-side, the DeserializeOwned trait does not support zero-copy deserialization. The deserialized type must not have lifetimes associated with the Deserializer. The "owned" means it doesn't borrow from anything. The cryptic error you get is due to the way DeserializeOwned is defined, it'll be implemented for any type that implements Deserialize for any lifetime, which will exclude types expecting a particular lifetime. This bound is used when lifetimes are unecessary or impossible to guarantee.

serde_json::from_reader is one of those cases. It only deserializes JSON from sources based on the Read trait. However, the Read trait makes no guarantees that any read data is referenceable after the fact. And thus from_reader dictates that T: DeserializeOwned to avoid that problem.

To take advantage of zero-copy deserialization, you'd need to use from_slice or from_str:

let data = std::fs::read_to_string(path)?;
let user: User = serde_json::from_str(&data)?;
Run Code Online (Sandbox Code Playgroud)

However, even if you do that, the data being referenced is local only to the read_object function. All data retrieved from the file is destroyed at the end of the function, and would leave user.name invalid if it were returned. The compiler would reject it (playground).

Without lifetimes, it works

And that's what I suggest you do; just use struct User { name: String }. I would advise against trying to use zero-cost deserialization from JSON strings at all because of escape sequences.