当我遇到这个有趣的场景时,我正在玩Rust闭包:
fn main() {
let mut y = 10;
let f = || &mut y;
f();
}
这给出了一个错误:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:4:16
|
4 | let f = || &mut y;
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime as defined on the body at 4:13...
--> src/main.rs:4:13
|
4 | let f = || &mut y;
| ^^^^^^^^^
note: ...so that closure can access `y`
--> src/main.rs:4:16
|
4 | let f = || &mut y;
| ^^^^^^
note: but, the lifetime must be valid for the call at 6:5...
--> src/main.rs:6:5
|
6 | f();
| ^^^
note: ...so type `&mut i32` of expression is valid during the expression
--> src/main.rs:6:5
|
6 | f();
| ^^^
即使编译器试图逐行解释它,我仍然不明白它到底在提示什么。
是否要说可变引用不能超过封闭包?
如果删除调用
f()
,编译器不会提示。
最佳答案
这里有两个主要的作用:
闭包返回对环境的引用
闭包不能返回
self
(闭包对象)的生存期的任何引用。这是为什么?每个闭包都可以称为FnOnce
,因为那是FnMut
的 super 特征,而这又是Fn
的 super 特征。 FnOnce
具有此方法:fn call_once(self, args: Args) -> Self::Output;
注意
self
是按值传递的。因此,由于self
已被消耗(并且现在位于call_once
函数中),我们无法返回对其的引用-等同于将引用返回给局部函数变量。从理论上讲,
call_mut
将允许返回对self
的引用(因为它接收到&mut self
)。但是由于call_once
,call_mut
和call
都是用同一主体实现的,因此闭包通常无法返回对self
的引用(即:对其捕获的环境的引用)。只是要确保:闭包可以捕获引用并将其返回!他们可以通过引用捕获并返回该引用。那些事情有些不同。它与闭包类型中存储的内容有关。如果类型中存储了引用,则可以将其返回。但是我们无法返回对封闭类型中存储的任何内容的引用。
嵌套可变引用
考虑一下此函数(请注意,参数类型暗含
'inner: 'outer
; 'outer
比'inner
短):fn foo<'outer, 'inner>(x: &'outer mut &'inner mut i32) -> &'inner mut i32 {
*x
}
这不会编译。乍一看,它似乎应该编译,因为我们只是剥离了一层引用。它确实适用于不可变的引用!但是,此处可变的引用在保留健全性方面有所不同。
不过,可以返回
&'outer mut i32
。但是,要获得更长(内部)生命周期的直接引用是不可能的。手动编写闭包
让我们尝试编写您要编写的闭包代码:
let mut y = 10;
struct Foo<'a>(&'a mut i32);
impl<'a> Foo<'a> {
fn call<'s>(&'s mut self) -> &'??? mut i32 { self.0 }
}
let mut f = Foo(&mut y);
f.call();
返回的引用应具有什么生命周期?
'a
,因为我们基本上有一个&'s mut &'a mut i32
。如上所述,在这种嵌套的可变引用情况下,我们无法提取更长的生命周期! 's
,因为这将意味着闭包在'self
的生命周期内返回某些内容(“从self
借用”)。而且如上所述,闭包不能做到这一点。 因此,编译器无法为我们生成闭包impls。
关于reference - 为什么我不能从闭包中返回对外部变量的可变引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65584936/