我是Rust的新手,看来我在这里严重缺少一些概念。
use std::thread;
fn main() {
let mut children = vec![];
//spawn threads
for i in 0..10 {
let c = thread::spawn(|| {
println!("thread id is {}", i);
});
children.push(c);
}
for j in children {
j.join().expect("thread joining issue");
}
}
它失败并显示以下错误:
error[E0373]: closure may outlive the current function, but it borrows `i`, which is owned by the current function
由于i
is的类型i32
,并且不涉及任何引用,Rust不应该复制该值而不是强制使用move
?
您原始问题的答案是println!
借用其论点。但是,正如您在注释中指出的那样,即使(显然)将整数移入闭包仍然会导致编译错误。
出于此答案的目的,我们将使用此代码。
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
为什么在x
那里借?不应该是副本吗?答案在于闭包的“捕获模式”。从文档中
编译器更喜欢通过不可变借项,唯一的不可变借项(见下文),可变借项以及最后通过移动来捕获封闭变量。它将选择允许闭包编译的首选方法。仅根据闭包表达式的内容进行选择;编译器不考虑周围的代码,例如所涉及变量的生存期。
正是由于x
具有Copy
类型,所以闭包本身可以仅用不可变的借位进行编译。鉴于不可改变的借x
(叫它bor
),我们可以做我们的分配_y
使用_y = *bor
。这不是“移出引用后的数据”,因为这是副本而不是移动。
但是,由于闭包借用了局部变量,因此它的类型将不是'static
,因此无法在use_closure
或中使用thread::spawn
。
尝试使用not类型的相同代码Copy
,实际上效果很好,因为强制闭包x
通过移动来捕获。
fn use_closure<F: FnOnce() + 'static>(_: F) {}
fn main() {
let x: Vec<i32> = vec![];
use_closure(|| {
let _y = x;
});
}
当然,您已经知道,解决方案是move
在闭包前面使用关键字。这将强制将所有捕获的变量移到闭包中。由于不会借用该变量,因此闭包将具有静态类型,并且可以在use_closure
或中使用thread::spawn
。
fn use_closure<F: FnOnce() + 'static>(_: F) {}
fn main() {
let x: i32 = 0;
use_closure(move || {
let _y = x;
});
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句