我正在尝试生成一组给定的线程,并且每个线程执行一个长时间运行的操作.我将一个结构传递给每个工作线程作为给定线程的内部状态.所述结构的集合保存在向量中,Master
结构的一部分.
编译器拒绝我将结构的内部成员传递给Arc::new()
:
use std::thread; use std::sync::Arc; struct Worker { name: String, } struct Master { workers: Vec, } impl Worker { fn start(&self) { println!("My name is {} and I'm working!", self.name); thread::sleep_ms(100_000); } } impl Master { pub fn run_test(&mut self) { for i in 0..10 { self.workers.push(Worker { name: String::new() + "Worker" + &i.to_string() }); } let mut data = Arc::new(self.workers); for i in 0..10 { let local_data = data.clone(); thread::spawn(move || { local_data[i].start(); }); } thread::sleep_ms(100_000); } } fn main() { let mut master = Master { workers: vec![] }; }
错误消息:
error[E0507]: cannot move out of borrowed content
--> :26:33
|
26 | let mut data = Arc::new(self.workers);
| ^^^^ cannot move out of borrowed content
我究竟做错了什么?这是惯用的Rust吗?
欢迎来到所有权.
在Rust中,任何单个数据都有一个且只有一个所有者.不要被愚弄Rc
和Arc
:它们是在单个(不可见)所有者的顶部共享接口.
表达所有权的最简单方式是按价值:
struct Master { workers: Vec}
在这里,Master
拥有一个Vec
本身拥有多个Worker
.
类似地,按值获取参数的函数(fn new(t: T) -> Arc
例如)接收其参数的所有权.
这就是问题所在:
Arc::new(self.workers)
意味着你同时:
声称Master
是该公司的所有者workers
声称Arc
是该公司的所有者workers
鉴于一个和一个所有者的统治,这显然是难以处理的.
那么,你如何欺骗并拥有一个单一数据的多个共同所有者?
好吧......用Rc
或者Arc
!
struct Master { workers: Arc> }
现在创建data
就像:
let data = self.workers.clone();
这会创建一个新的Arc
(只会碰到引用计数).
但这并不是全部.借款系统的核心原则是:别名XOR Mutability.
由于Arc
是混叠,它可以防止可变性.你不能再插入工人了self.workers
!
有多种解决方案,例如推迟初始化self.workers
直到构建向量,但最常见的是使用单元格或互斥体,即Rc
或Arc
(或Arc
).
RefCell
并且Mutex
是将借用检查从编译时移动到运行时的包装器.这提供了更多的灵活性,但可能导致运行时混乱而不是编译时错误,因此最好用作最后的手段.