我试图更深入地理解rust是如何工作的。我试图做一些序列化和反序列化来保存和加载一个泛型类型的结构体。我让它工作了,但是我不理解HRTB以及他们为什么让代码工作。最初我有这个
use serde::Deserialize;
use bincode;
use std::fs;
#[derive(Deserialize)]
pub struct Construct<T> {
data: Vec<T>
}
impl <'a, T: Deserialize<'a>> Construct<T> {
pub fn load() -> Self {
match fs::read("data.sav") {
Ok(d) => {
let c: Construct<T> = bincode::deserialize(&d).unwrap();
c
},
Err(e) => {
println!("{e}, passing empty Construct");
Self { data: Vec::new() }
}
}
}
}
产生此错误的原因
error[E0597]: `d` does not live long enough
--> src/main.rs:14:49
|
10 | impl <'a, T: Deserialize<'a>> Construct<T> {
| -- lifetime `'a` defined here
...
14 | let c: Construct<T> = bincode::deserialize(&d).unwrap();
| ---------------------^^-
| | |
| | borrowed value does not live long enough
| argument requires that `d` is borrowed for `'a`
15 | c
16 | },
| - `d` dropped here while still borrowed
我已经修复了impl块,以接受更高排名的特性绑定。而且它工作得很好。
...
impl <T: for<'a> Deserialize<'a>> Construct<T> {
pub fn load() -> Self {
...
据我所知,Deserialize需要确保input引用与out结构一样长(https://serde.rs/lifetimes.html),在第一个例子中声明trait和使用for〈'a〉的区别在于,在第一个例子中,调用者提供了生存期,而for〈'a〉从impl本身获取生存期。(How does "for<>" syntax differ from a regular lifetime bound?)我认为使用for〈'a〉语法可以从实现块中获得生命周期,这比调用函数获得更长的生命周期,对吗?有没有其他方法可以不使用HRTB来编写这个load函数?
1条答案
按热度按时间6kkfgxo01#
我认为使用for〈'a〉语法可以从实现块中获取生命周期,对吗
是的,从调用
bincode::deserialize(&d)
。具体地说,d
的生存期。这就比调用函数的生命周期长
不是,更短的:不是调用者决定的寿命(其将总是比
d
的寿命长(因为它在我们的函数内声明)),而是得到仅d
的寿命。有没有其他不使用HRTB的方法来编码这个加载函数?
是的,通过将
T
绑定到DeserializeOwned
。但这只是隐藏了HRTB:DeserializeOwned
在幕后使用它们。