如果 let borrow 在 return 之后即使有 #![feature(nll)]
If let borrow stays after return even with #![feature(nll)]
我正在处理一个大文件,但这是一个导致同样问题的小玩具示例。抱歉,如果示例本身没有意义。
#![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();
}
让我们在这里详细了解一下生命周期。函数 foo()
被脱糖为
fn foo<'a>(&'a mut self) -> Option<&'a i32>
即returned 值最多存在 self
; bar()
.
也类似
在foo()
中,行
if let Some(val) = self.bar() {
借用了 self
的生命周期 'b
,returned 引用 val
也有此生命周期 'b
。既然你那么returnSome(val)
,生命周期'b
肯定比self
参数foo()
的生命周期'a
长,肯定比foo()
的运行时间。这意味着您以后无法在 foo()
.
中再次借用 self
我认为这个例子中令人惊讶的是 self
的借位甚至发生在 bar()
returns None
的情况下。直觉上,我们觉得在这种情况下没有引用 returned,所以我们不需要借用。然而,Rust 中的生命周期是由类型检查器检查的,而类型检查器不理解类型的不同值的含义。由 bar()
编辑的值 return 具有类型 Option<&'b i32>
,无论它是 returns None
还是 Some
,并且生命周期 'b
必须至少与 'a
一样长 – 鉴于限制,没有其他解决方案,因此借用检查器必须拒绝这个。
对于非词法生命周期,编译器可以引入更灵活的生命周期,这些生命周期不受词法作用域的约束,并且可以以以前不可能的方式重叠。但是,如果根本没有满足所有约束的生命周期,NLL 将无济于事。
您给出的最后一个代码片段完全不同。让我们添加生命周期:
if self.bar<'b>().is_some() {
return self.bar<'c>();
}
现在我们调用 bar()
两次,每次调用都可以有不同的生命周期。现在只有生命周期 'c
需要比 'a
长,但生命周期 'b
只需要足够长以对结果调用 is_some()
。生命周期为 'c
的借用只在分支被取时发生,不会发生冲突。
我正在处理一个大文件,但这是一个导致同样问题的小玩具示例。抱歉,如果示例本身没有意义。
#![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();
}
让我们在这里详细了解一下生命周期。函数 foo()
被脱糖为
fn foo<'a>(&'a mut self) -> Option<&'a i32>
即returned 值最多存在 self
; bar()
.
在foo()
中,行
if let Some(val) = self.bar() {
借用了 self
的生命周期 'b
,returned 引用 val
也有此生命周期 'b
。既然你那么returnSome(val)
,生命周期'b
肯定比self
参数foo()
的生命周期'a
长,肯定比foo()
的运行时间。这意味着您以后无法在 foo()
.
self
我认为这个例子中令人惊讶的是 self
的借位甚至发生在 bar()
returns None
的情况下。直觉上,我们觉得在这种情况下没有引用 returned,所以我们不需要借用。然而,Rust 中的生命周期是由类型检查器检查的,而类型检查器不理解类型的不同值的含义。由 bar()
编辑的值 return 具有类型 Option<&'b i32>
,无论它是 returns None
还是 Some
,并且生命周期 'b
必须至少与 'a
一样长 – 鉴于限制,没有其他解决方案,因此借用检查器必须拒绝这个。
对于非词法生命周期,编译器可以引入更灵活的生命周期,这些生命周期不受词法作用域的约束,并且可以以以前不可能的方式重叠。但是,如果根本没有满足所有约束的生命周期,NLL 将无济于事。
您给出的最后一个代码片段完全不同。让我们添加生命周期:
if self.bar<'b>().is_some() {
return self.bar<'c>();
}
现在我们调用 bar()
两次,每次调用都可以有不同的生命周期。现在只有生命周期 'c
需要比 'a
长,但生命周期 'b
只需要足够长以对结果调用 is_some()
。生命周期为 'c
的借用只在分支被取时发生,不会发生冲突。