你原来问题的答案是println!借用其论据。 https://stackoverflow.com/questions/30450399/does-println-borrow-or-own-the-variable但是,正如您在评论中指出的那样,即使(显然)将整数移动到闭包中仍然会导致编译错误。
出于本答案的目的,我们将使用此代码。
fn use_closure<F: FnOnce() + 'static>(_: F) {}
fn main() {
let x: i32 = 0;
use_closure(|| {
let _y = x;
});
}
use_closure
模拟什么thread::spawn
原始代码中的作用:它消耗一个类型必须是的闭包'static
.
尝试编译此错误
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
--> src/main.rs:5:17
|
5 | use_closure(|| {
| ^^ may outlive borrowed value `x`
6 | let _y = x;
| - `x` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:5:5
|
5 | / use_closure(|| {
6 | | let _y = x;
7 | | });
| |______^
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
5 | use_closure(move || {
| ^^^^^^^
等等,什么?
6 | let _y = x;
| - `x` is borrowed here
Why is x
那里借的?不应该是复印件吗?答案在于闭包的“捕获模式”。从文档 https://doc.rust-lang.org/reference/types/closure.html#capture-modes
编译器更喜欢通过不可变借用捕获封闭变量,然后是唯一的不可变借用(见下文),通过可变借用,最后通过移动。它将选择允许闭包编译的第一个选择。该选择仅针对闭包表达式的内容进行;编译器不考虑周围的代码,例如所涉及变量的生命周期。
正是因为x
has a Copy
类型,闭包本身可以通过不可变的借用进行编译。给定一个不可变的借用x
(叫它bor
),我们可以做我们的任务_y
with _y = *bor
。这不是“移出引用后面的数据”,因为这是副本而不是移动。
然而,由于闭包借用了一个局部变量,它的类型不会是'static
,所以它不能用于use_closure
or thread::spawn
.
使用不同的类型尝试相同的代码Copy
,它实际上工作得很好,因为闭包被强制捕获x
通过移动它。
fn use_closure<F: FnOnce() + 'static>(_: F) {}
fn main() {
let x: Vec<i32> = vec![];
use_closure(|| {
let _y = x;
});
}
当然,正如您所知,解决方案是使用move
闭包前面的关键字。这会强制将所有捕获的变量移至闭包中。由于变量不会被借用,因此闭包将具有静态类型并且能够在use_closure
or thread::spawn
.
fn use_closure<F: FnOnce() + 'static>(_: F) {}
fn main() {
let x: i32 = 0;
use_closure(move || {
let _y = x;
});
}