我正在处理一个大文件,但这是一个导致相同问题的小型玩具示例。很抱歉,示例本身没有意义。
#![feature(nll)]
struct S(i32);
impl S {
fn foo(&mut self) -> Option<&i32> {
if let Some(val) = self.bar() {
return Some(val);
}
let y = &mut self.0;
None
}
fn bar(&mut self) -> Option<&i32> {
None
}
}
fn main() {
S(0).foo();
}
这没有通过借阅检查器:
error[E0499]: cannot borrow `self.0` as mutable more than once at a time
--> test.rs:9:17
|
6 | if let Some(val) = self.bar() {
| ---- first mutable borrow occurs here
...
9 | let y = &mut self.0;
| ^^^^^^^^^^^ second mutable borrow occurs here
|
note: first borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 5:5...
--> test.rs:5:5
|
5 | / fn foo(&mut self) -> Option<&i32> {
6 | | if let Some(val) = self.bar() {
7 | | return Some(val);
8 | | }
9 | | let y = &mut self.0;
10| | None
11| | }
| |_____^
由于它是在#![feature(nll)]
块中返回的,这是否有效(即使没有if let
)?值得注意的是,如果将if let
块更改为以下代码,则可以正常编译
if self.bar().is_some() {
return self.bar();
}
答案 0 :(得分:3)
让我们在这里详细了解生命周期。函数foo()
被减为
fn foo<'a>(&'a mut self) -> Option<&'a i32>
即返回值的生存期最长为self
;对于bar()
也是如此。
在foo()
中,该行
if let Some(val) = self.bar() {
创建借用的self
,该借用的生存期为'b
,并且返回的引用val
的生存期为'b
。自从您返回Some(val)
以来,生存期'b
必须比'a
参数的生存期self
到foo()
更长,这肯定比{ {1}}。这意味着您以后不能再在foo()
中借用self
。
我认为在此示例中令人惊讶的是,即使foo()
返回self
也会发生bar()
的借用。直觉上,在这种情况下,我们认为没有引用返回,因此我们不需要借用。但是,Rust中的生存期由类型检查器检查,并且类型检查器不理解类型的不同值的含义。 None
返回的值的类型为bar()
,而不管返回的是Option<&'b i32>
还是None
,并且生存期Some
至少应与'b
–鉴于约束,没有其他解决方案,因此借阅检查员必须拒绝这样做。
使用非词汇生存期,编译器可以引入更灵活的生存期,这些生存期不受词汇范围的约束,并且可以以以前无法实现的方式重叠。但是,如果没有寿命可以满足所有约束条件,那么NLL将无济于事。
您提供的最后一个代码段是完全不同的。让我们添加生命周期:
'a
现在,我们两次呼叫if self.bar<'b>().is_some() {
return self.bar<'c>();
}
,并且这些呼叫中的每一个都有不同的生存期。现在,只有生存期bar()
才需要延长'c
的寿命,但是生存期'a
只需要足够长的时间就可以对结果调用'b
。寿命为is_some()
的借用仅在进行分支时发生,并且不会发生冲突。