当我遇到这个有趣的场景时,我正在玩 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()
,编译器不会提示。 最佳答案
精简版
闭包 f
存储对 y
的可变引用。如果允许返回此引用的副本,您最终会同时获得两个对 y
的可变引用(一个在闭包中,一个返回),这是 Rust 的内存安全规则所禁止的。
长版
闭包可以被认为是
struct __Closure<'a> {
y: &'a mut i32,
}
因为它包含一个可变引用,所以闭包被称为
FnMut
,本质上与定义fn call_mut(&mut self, args: ()) -> &'a mut i32 { self.y }
因为我们只有一个对闭包本身的可变引用,所以我们不能将字段
y
移出借用的上下文,我们也不能复制它,因为可变引用不是 Copy
。我们可以通过强制将闭包调用为
FnOnce
而不是 FnMut
来欺骗编译器接受代码。这段代码工作正常:fn main() {
let x = String::new();
let mut y: u32 = 10;
let f = || {
drop(x);
&mut y
};
f();
}
由于我们在闭包范围内消费
x
并且 x
不是 Copy
,编译器检测到闭包只能是 FnOnce
。调用 FnOnce
闭包会按值传递闭包本身,因此我们可以将可变引用移出。强制闭包为
FnOnce
的另一种更明确的方法是将其传递给具有 trait bound 的泛型函数。这段代码也能正常工作:fn make_fn_once<'a, T, F: FnOnce() -> T>(f: F) -> F {
f
}
fn main() {
let mut y: u32 = 10;
let f = make_fn_once(|| {
&mut y
});
f();
}
关于reference - 为什么我不能从闭包返回对外部变量的可变引用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57748424/