下面的这段代码,中15行的t
(出借方)的生命周期明显小于借用方u
,但是为啥编译可以通过呢?我用了PhantomData<&'a T>的
#[derive(Debug)]
struct User<'a, T: Debug + 'a> {
age: u8,
data: *const T,
_marker: PhantomData<&'a T>
}
#[derive(Debug)]
struct Test {
v: Box<i32>
}
let u;
{
let t = Test {
v: Box::new(1)
};
u = User {
age: 1,
data: &t as *const Test,
_marker: PhantomData
};
};
println!("data: {:?}", unsafe { u.data });
但是下面这段代码就可以成功检测到生命周期的问题:
#[derive(Debug)]
struct User<'a, T: Debug + 'a> {
age: u8,
data: *const T,
_marker: PhantomData<&'a T>
}
#[derive(Debug)]
struct Test {
v: Box<i32>
}
fn create_user(t: &Test) -> User<Test> {
User {
age: 1,
data: t as *const Test,
_marker: PhantomData
}
}
let u;
{
let t = Test {
v: Box::new(1)
};
u = create_user(&t);
};
println!("data: {:?}", unsafe { u.data });
报错信息:
error[E0597]: `t` does not live long enough
--> src/main.rs:89:26
|
89 | u = create_user(&t);
| ^^ borrowed value does not live long enough
90 | };
| - `t` dropped here while still borrowed
91 | println!("data: {:?}", unsafe { u.data });
| ------ borrow later used here
1
共 6 条评论, 1 页
评论区
写评论User::data 是个原生指针,而原生指针没有生命周期。
PhantomData<&'a T>只是行为像是拥有这个T,但其实并没有。 你可以实现drop trait,看看什么时候drop的,而且你的
data: t as *const Test
其实已经是空指针了,ptr::read(data),拿到的不是1了@solarsail
同意这个说法
个人觉得 @whfuyn 说的有道理。
data: &t as *const Test
这里是不检查生命周期的,borrow checker 不管 raw pointer。第一种方式,
User
是现场创建的,PhantomData<&'a T>
中的'a
和t
的生命周期没关系,编译器认为 ok。第二种方式如 @whfuyn 所说,
create_user
函数把参数和返回值的生命周期联系起来了,t: &'a Test
和User<'a, Test>
共用了'a
,所以检查不通过。lifetime应该是针对引用而言的,非引用类型T: 'a让我觉得很可疑。 第一段编译通过的代码:
我认为这句
data: &t as *const Test
根本没有让User<'a, T: Debug + 'a>
的'a
和&t
的生命周期一致,甚至有可能为了让编译通过推导出这个'a应该更长。 而第二段代码:实际上应该是
fn create_user<'a>(t: &'a Test) -> User<Test>
,根据The Book上关于生命周期省略的规则The second rule is if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameter
返回的User的生命周期被推断为和t一致,所以之后才会报错说生命周期不够长。以上是我个人的看法,水平有限,我不确定对不对,看看别的朋友怎么说。
确实是, 通过一个函数构造就可以正常检测到生命周期.