在Rust中,我收到以下错误:
<anon>:14:9: 14:17 error: `mystruct` does not live long enough
<anon>:14 mystruct.update();
^~~~~~~~
<anon>:10:5: 17:6 note: reference must be valid for the lifetime 'a as defined on the block at 10:4...
<anon>:10 {
<anon>:11 let initial = vec![Box::new(1), Box::new(2)];
<anon>:12 let mystruct = MyStruct { v : initial, p : &arg };
<anon>:13
<anon>:14 mystruct.update();
<anon>:15
...
<anon>:12:59: 17:6 note: ...but borrowed value is only valid for the block suffix following statement 1 at 12:58
<anon>:12 let mystruct = MyStruct { v : initial, p : &arg };
<anon>:13
<anon>:14 mystruct.update();
<anon>:15
<anon>:16 mystruct
<anon>:17 }
error: aborting due to previous error
代码如下:
struct MyStruct<'a>
{
v : Vec<Box<i32>>,
p : &'a i32
}
impl<'a> MyStruct<'a>
{
fn new(arg : &'a i32) -> MyStruct<'a>
{
let initial = vec![Box::new(1), Box::new(2)];
let mystruct = MyStruct { v : initial, p : &arg };
mystruct.update();
mystruct
}
fn update(&'a mut self)
{
self.p = &self.v.last().unwrap();
}
}
fn main() {
let x = 5;
let mut obj = MyStruct::new(&x);
}
我不明白为什么mystruct
不够活跃。如果我注释掉mystruct.update()
行,它可以正常工作。更重要的是,如果我注释掉update
的主体代码仍然失败。为什么调用一个借用可变self
的空函数会改变一些东西?
我不明白哪个引用是错误所涉及的引用。有人可以解释一下吗?
答案 0 :(得分:8)
此错误所引用的引用是在您调用update()
时隐式创建的引用。由于update()
需要&'a mut self
,因此它表示它接受&'a mut MyStruct<'a>
类型的值。这意味着理论上你应该像这样调用update()
:
(&mut mystruct).update();
在任何地方写这个都非常不方便,因此Rust能够自动插入必要的&
s,&mut
和*
以调用方法。这被称为&#34; autoreference&#34;,它发生的唯一地方是方法调用/字段访问。
问题是update()
方法的定义:
impl<'a> MyStruct<'a> {
...
fn update(&'a mut self) { ... }
...
}
此处,您要求update()
通过带有生命周期'a
的引用接收其调用的值,其中'a
是存储在结构中的引用的生命周期。
但是,如果您有一个结构值,而您正在调用此方法,则应该已存在对此结构中存储的i32
的引用。因此,结构值的生命周期严格小于生命周期参数指定的生命周期,因此用局部变量构造&'a mut MyStruct<'a>
是不可能的(如你的情况)。
解决方案是使用&mut self
代替&'a mut self
:
fn update(&mut self) { ... }
// essentially equivalent to
fn update<'b>(&'b mut self) where 'a: 'b { ... }
// `'b` is a fresh local lifetime parameter
这样,此方法调用中结构的生命周期与此结构包含的引用无关,并且可以更小。
下面将进行更深入的解释。
你自己的定义本身并不是无稽之谈。例如:
struct IntRefWrapper<'a> {
value: &'a i32
}
static X: i32 = 12345;
static Y: IntRefWrapper<'static> = IntRefWrapper { value: &X };
impl<'a> IntRefWrapper<'a> {
fn update(&'a self) { ... }
}
Y.update();
此处update()
调用不会导致编译错误,因为Y
和[{1}}的生命周期(X
中包含的引用){ {1}}。
让我们考虑你的例子,进行比较:
Y
这里我们有一个生命周期参数'static
,它由函数的调用者提供。例如,调用者可以使用静态引用调用此函数:
impl<'a> MyStruct<'a> {
fn new(arg : &'a i32) -> MyStruct<'a> {
let initial = vec![Box::new(1), Box::new(2)];
let mystruct = MyStruct { v : initial, p : &arg };
mystruct.update();
mystruct
}
}
但是,当调用'a
方法时,static X: i32 = 12345;
MyStruct::new(&X); // here &X has static lifetime
生命周期受到调用它的块的限制:
update()
当然,借阅检查员无法证明此生命周期与来电者提供的生命周期相同(对于任何可能的&#34;外部&#34;生命周期,他们确实无法匹配) ,所以它会引发错误。
当更新定义如下:
mystruct
然后当你调用它时,不再需要你调用此方法的值必须与{
let initial = vec![Box::new(1), Box::new(2)];
let mystruct = MyStruct { v : initial, p : &arg }; // +
// |
mystruct.update(); // |
// |
mystruct // |
}
一样长 - 它足以让它在任何小于或等于的生命周期中存活到fn update(&mut self) { ... }
// or, equivalently
fn update<'b>(&'b mut self) where 'a: 'b { ... }
- 函数内部的生命周期完全符合这些要求。因此,您可以在您的值上调用此类方法,编译器不会抱怨。
另外(正如评论中所注意到的)以下行确实无效,并且无法绕过它:
'a
借用检查在此处失败,因为您试图将具有结构生命周期的引用存储到结构本身中。一般来说,这是不可能的,因为它有令人讨厌的健全性问题。例如,假设您确实能够将此引用存储到结构中。但是现在你不能在结构中变异'a
,因为它可能会破坏先前存储的引用所指向的元素,从而使代码内存不安全。
无法静态检查这些内容,因此在借用检查级别上不允许这样做。事实上,这只是一般借款检查规则的一个很好的结果。