gpt4 book ai didi

rust - 为什么 Rust 在生成线程时强制在 i32 情况下使用 move?

转载 作者:行者123 更新时间:2023-12-02 07:16:39 26 4
gpt4 key购买 nike

我是 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 的类型是 i32 ,并且没有涉及引用,Rust 不应该复制值而不是强制 move

最佳答案

您最初问题的答案是 println! borrows its arguments.但是,正如您在评论中指出的那样,即使(显然)将整数移动到闭包中仍然会导致编译错误。

出于此答案的目的,我们将使用此代码。

fn use_closure<F: FnOnce() + 'static>(_: F) {}

fn main() {
let x: i32 = 0;
use_closure(|| {
let _y = x;
});
}

(playground)

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那里借的?不应该是副本吗?答案在于闭包的“捕获模式”。来自 the documentation

The compiler prefers to capture a closed-over variable by immutable borrow, followed by unique immutable borrow (see below), by mutable borrow, and finally by move. It will pick the first choice of these that allows the closure to compile. The choice is made only with regards to the contents of the closure expression; the compiler does not take into account surrounding code, such as the lifetimes of involved variables.

正是因为x有一个 Copy类型,闭包本身可以通过不可变的借用进行编译。给定一个不可变的借用 x (称之为 bor ),我们可以对 _y 进行分配与 _y = *bor .这不是“移出引用后面的数据”,因为这是复制而不是移动。

然而,由于闭包借用了一个局部变量,它的类型不会是'static。 , 所以它不能在 use_closure 中使用或 thread::spawn .

尝试使用非 Copy 类型的相同代码, 它实际上工作得很好,因为闭包被强制捕获 x通过移动它。

fn use_closure<F: FnOnce() + 'static>(_: F) {}

fn main() {
let x: Vec<i32> = vec![];
use_closure(|| {
let _y = x;
});
}

(playground)


当然,如您所知,解决方案是使用 move闭包前的关键字。这会强制将所有捕获的变量移动到闭包中。由于变量不会被借用,闭包将具有静态类型并且能够在 use_closure 中使用。或 thread::spawn .

fn use_closure<F: FnOnce() + 'static>(_: F) {}

fn main() {
let x: i32 = 0;
use_closure(move || {
let _y = x;
});
}

(playground)

关于rust - 为什么 Rust 在生成线程时强制在 i32 情况下使用 move?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61320595/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com