示例讲解
在闭包章节中,有讲过 move
关键字在闭包中的使用可以让该闭包拿走环境中某个值的所有权,同样地,你可以使用 move
来将所有权从一个线程转移到另外一个线程。
首先,来看看在一个线程中直接使用另一个线程中的数据会如何:
use std::thread;fn main() {let v = vec![1, 2, 3];let handle = thread::spawn(|| {println!("Here's a vector: {:?}", v);});handle.join().unwrap();
}
以上代码在子线程的闭包中捕获了环境中的 v 变量,来看看结果:
其实代码本身并没有什么问题,问题在于 Rust 无法确定新的线程会活多久。
我们把代码改成这样
use std::thread;fn main() {let v = vec![1, 2, 3];let handle = thread::spawn(move || {println!("Here's a vector: {:?}", v);});handle.join().unwrap();// 下面代码会报错borrow of moved value: `v`// println!("{:?}",v);
}
move关键字
在 Rust 中,move
关键字用于显式地指示编译器,闭包或函数应该获取(move)其作用域内的所有变量的所有权,而不是仅仅借用它们。这在处理多线程或需要将变量所有权转移给另一个作用域的情况下特别有用。
在上面的代码示例中,move
关键字被用在 thread::spawn
函数的闭包参数前。这意味着闭包将拥有并带走所有在其作用域内可访问的变量的所有权,包括 tx
(通道的发送端)。这是因为闭包将在新线程中运行,而 Rust 的所有权规则不允许跨线程借用变量,因为这可能导致数据竞争和不安全的状态。
如果不使用 move
关键字,编译器会报错,因为你试图在闭包外部和内部同时使用 tx
。使用 move
后,tx
的所有权被移动到闭包中,因此在闭包执行完毕之前,你在主线程中无法再使用 tx
。这就是为什么在这个例子中,tx
在 thread::spawn
调用之后不能再被使用的原因。
总结一下 move
的作用:
- 它允许闭包或函数获取其捕获的变量的所有权。
- 这使得可以将变量的所有权安全地转移到另一个作用域,例如另一个线程。
- 使用
move
的闭包被称为“移动闭包”,并且不能被调用多次,因为一旦它获取了变量的所有权,这些变量就不能再次被移动。