我正在尝试生成一组给定的线程,并且每个线程执行一个长时间运行的操作。我将一个结构传递给每个工作线程作为给定线程的内部状态。所述结构的集合保存在向量中,是Master
结构的一部分。
编译器拒绝我将结构的内部成员传递给Arc::new()
:
use std::thread;
use std::sync::Arc;
struct Worker {
name: String,
}
struct Master {
workers: Vec<Worker>,
}
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
--> <anon>:26:33
|
26 | let mut data = Arc::new(self.workers);
| ^^^^ cannot move out of borrowed content
我做错了什么?这是惯用的Rust吗?
答案 0 :(得分:6)
欢迎使用所有权。
在Rust中,任何单个数据都有一个且只有一个所有者。不要被Rc
和Arc
愚弄:它们是单个(不可见)所有者之上的共享界面。
表达所有权的最简单方法是按值:
struct Master {
workers: Vec<Worker>
}
此处,Master
拥有Vec<Worker>
,其本身拥有多个Worker
。
类似地,按值(例如fn new(t: T) -> Arc<T>
)获取参数的函数会获得其参数的所有权。
这就是问题所在:
Arc::new(self.workers)
意味着你同时:
Master
是workers
Arc
是workers
鉴于一个且只有一个所有者的规则,这显然是难以处理的。
那么,你如何欺骗并拥有一个单一数据的多个共同所有者?
嗯...使用Rc
或Arc
!
struct Master {
workers: Arc<Vec<Worker>>
}
现在创建data
非常简单:
let data = self.workers.clone();
会创建一个新的Arc
(只会碰到引用计数)。
由于Arc
是关于别名的,因此会阻止可变性。您不能再将工作人员插入self.workers
了!
有多种解决方案,例如在构建向量之前推迟self.workers
的初始化,但最常见的是使用单元格或互斥锁,即Rc<RefCell<T>>
或Arc<Mutex<T>>
(或Arc<RwLock<T>>
)。
RefCell
和Mutex
是将借用检查从编译时移动到运行时的包装器。这提供了更多的灵活性,但可能导致运行时混乱而不是编译时错误,因此最好用作最后的手段。