任何人都可以通过以下代码说出问题所在吗?编译器抱怨生命周期,但错误消息绝对没有意义。我已经尝试了所有我能想到的东西,但似乎没有任何帮助。
use std::borrow::BorrowMut;
trait Trait<'a> {
fn accept(&mut self, &'a u8);
}
struct Impl<'a>{
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {
fn accept(&mut self, inp: &'a u8) { self.myref = Some(inp); }
}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl{myref: None})
}
fn user<'a>(obj: &mut Trait<'a>) {}
fn parent<'a>(x: &'a u8) {
let mut pool = new();
user(pool.borrow_mut());
}
编译器错误是
error: `pool` does not live long enough
--> src/wtf.rs:22:10
|
22 | user(pool.borrow_mut());
| ^^^^ does not live long enough
23 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
这绝对没有意义。借款人的生活如何?我甚至没有使用借来的价值!
答案 0 :(得分:10)
好的,这个确实有意义,但由于终身省略而很难看到。所以,这里的代码是所有明确写出的生命周期,并且无关的细节被剔除:
use std::borrow::BorrowMut;
trait Trait<'a> {}
struct Impl<'a> {
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl { myref: None })
}
fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'b)) {}
fn parent() {
/* 'i: */ let mut pool/*: Box<Trait<'x> + 'x>*/ = new();
/* 'j: */ let pool_ref/*: &'i mut Box<Trait<'x> + 'x>*/ = &mut pool;
/* BorrowMut<T>::borrow_mut<'d>(&'d mut Self) -> &'d mut T */
/* 'k: */ let pool_borrow/*: &'i mut (Trait<'x> + 'x)*/ = Box::borrow_mut(pool_ref);
user(pool_borrow);
}
现在,从parent
的最后一行的角度来看,我们可以通过阅读user
的定义并替换parent
中的生命周期来计算出以下等价:
'a
= 'x
'b
= 'i
'b
= 'x
此外,这让我们得出结论:
'x
= 'i
这就是问题所在。由于您已定义user
的方式,您已将自己置于pool_ref
借用的生命周期(等于{{1}的生命周期)的情况中您要借用的存储位置必须与pool
中存储中使用的生存期'x
相同。
有点像pool
能够在它存在之前拥有指向自身的指针,这没有任何意义。
无论哪种方式,修复都很简单。将Box
更改为实际具有正确的类型:
user
这匹配fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'a)) {}
生成的类型。或者,不要使用new
:
borrow_mut
此有效,因为它是&#34;重新借用&#34;。调用user(&mut *pool)
或多或少地直接转换生命周期,但重新借用允许编译器将借用缩小到更短的生命周期。换句话说,明确地调用borrow_mut
并不能让编译器有足够的自由去软化&#34;使他们全部排队的生命周期,重新借用 。
快速搁置:
我甚至没有使用借来的价值!
不相关。 Rust在本地完成完全的类型和生命周期检查。 永远不会查看另一个函数的主体,看看它在做什么;它仅在界面上进行。编译器既不检查也不关心你在里面做一个不同的函数。
答案 1 :(得分:4)
请注意,错误消息还有更多内容:
error: `pool` does not live long enough
--> src/main.rs:25:10
|>
25 |> user(pool.borrow_mut());
|> ^^^^
note: reference must be valid for the block at 23:25...
--> src/main.rs:23:26
|>
23 |> fn parent<'a>(x: &'a u8) {
|> ^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 24:25
--> src/main.rs:24:26
|>
24 |> let mut pool = new();
|> ^
让我们看一下user
:
fn user<'a>(obj: &mut Trait<'a>) {}
这表示它将接受一个带有生命期'a
参数化的特征对象的可变引用(具有未命名的生命周期)。
转向new
,我会说这种方法高度可疑:
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl { myref: None })
}
这表示它将返回一个盒装特征对象,其中调用者指定的任何生命周期。 That basically never makes sense。
所有这一切,我不清楚为什么代码选择使用borrow_mut
。我会更直接地写出来:
user(&mut *pool);
取消引用Box<Trait>
获取Trait
,然后获取可变参考,产生&mut Trait
,编译。
我目前无法解释为什么BorrowMut
的行为不同。
答案 2 :(得分:2)
我不确定为什么会发生此错误,但我可以提供解决方案!
首先,似乎使用borrow_mut
会不必要地限制返回引用的生命周期。使用运算符创建引用可以解决错误。
fn parent() {
let mut pool = new();
user(&mut *pool);
}
但是,如果我们不这样做,我们可以通过在Trait
&#39;中添加user
对象的生命周期来解决错误。 s obj
参数。
fn user<'a>(obj: &mut (Trait<'a> + 'a)) {}