我不确定为什么以下代码无法编译。
use std::cmp::Ordering;
struct MyItr<'a> {
cur: &'a i32,
}
impl<'a> Ord for MyItr<'a> {
fn cmp(&self, other: &MyItr) -> Ordering {
self.cur.cmp(&other.cur)
}
}
impl<'a> PartialOrd for MyItr<'a> {
fn partial_cmp(&self, other: &MyItr<'a>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> PartialEq for MyItr<'a> {
fn eq(&self, other: &MyItr) -> bool {
self.cur == other.cur
}
}
impl<'a> Eq for MyItr<'a> {}
fn f0<'a>(t0: &'a mut MyItr<'a>, t1: &'a mut MyItr<'a>, i: &'a i32) {
let t = std::cmp::max(t0, t1);
t.cur = i;
}
fn f1() {
let i0 = 1;
let i1 = 2;
let mut z0 = MyItr { cur: &i0 };
let mut z1 = MyItr { cur: &i1 };
let i2 = 3;
f0(&mut z0, &mut z1, &i2);
}
$ cargo build
Compiling foo v0.1.0 (file:///private/tmp/foo)
error: `z1` does not live long enough
--> lib.rs:40:1
|
39 | f0(&mut z0, &mut z1, &i2);
| -- borrow occurs here
40 | }
| ^ `z1` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
我的理解是,一旦
z0
调用结束,就会备份借用的z1
和f0
引用。但是,编译器似乎假定不支持借用的引用。$ cargo --version
cargo 0.20.0-nightly (41e490480 2017-05-16)
最佳答案
这里有两个问题。首先是您指定了生存期,从而造成了编译器无法处理的情况。
fn f0<'a>(t0: &'a mut MyItr<'a>, t1: &'a mut MyItr<'a>, i: &'a i32)
您已经告诉编译器,所有参数都必须是具有相同生存期的指针。编译器可以缩短重叠的生存期,但是在这种情况下没有帮助。您已指定
MyItr
的指针与它们所指向的对象具有相同的生存期,并且外部指针是可变的。第二个问题是(即使解决了这个问题),您尝试做的事情完全是不安全的,并且会导致指针悬空。
这是一个更简单的示例:
struct S<'a> {
ptr: &'a i32,
}
fn f<'b>(t: &'b mut S<'b>, new_ptr: &'b i32) {}
fn main() {
let i0 = 1;
let mut s = S { ptr: &i0 };
let i1 = 2;
f(&mut s, &i1);
}
什么是
'b
?好的,编译器只能缩短生命周期,因此通常您只需要尝试传递的所有事物的生命周期,然后选择最短的生命周期。在这种情况下,这就是i1
的生命周期。因此,它必须缩短&s
的生存期。指向s
本身的指针的生存期不是问题(您可以缩小借用的时间),但是缩小内部生存期(用于ptr
字段的生存期)是一个问题。如果编译器缩小了
s.ptr
的生存期,则可以将&i1
存储在该字段中。 s
期望s.ptr
自身生命周期更长,但这不再成立:i1
将在s
之前销毁,这意味着s.ptr
将包含一个悬空指针。而且Rust不会允许这种情况发生。结果,Rust无法缩小
s
的内部'a
的生存期...但是,如果无法缩小它的范围,则意味着'b
必须是完整的,未缩小的'a
。但是,等等,这意味着'b
比s
本身和i1
的生存期更长。那是不可能的。因此失败了。
该解决方案需要两件事。首先,您不必过多指定生存期。其次,您需要确保所有有效生命周期都存在。对于您的原始代码,这意味着将
i2
移到z0
和z1
上方,以使其生命周期更长。像这样:fn f0<'a>(t0: &mut MyItr<'a>, t1: &mut MyItr<'a>, i: &'a i32) {
let t: &mut MyItr<'a> = std::cmp::max(t0, t1);
t.cur = i;
}
fn f1() {
let i0 = 1;
let i1 = 2;
let i2 = 3;
let mut z0 = MyItr { cur: &i0 };
let mut z1 = MyItr { cur: &i1 };
f0(&mut z0, &mut z1, &i2);
}
一条经验法则:不要在任何地方都发送垃圾邮件。对于应该相同的事物,只能使用相同的生命周期。
关于rust - 如何解决生存期错误以在Rust中进行可变引用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44081272/