#[derive(Debug)] struct fork{}
static PHILOSOPHERS: &[&str] = &["Socrates", "Hypatia", "Plato", "Aristotle", "Pythagoras"];
fn main() {
let mut hanlders = Vec::new();
hanlders.push(fork{});
// Make each of them think and eat 100 times
for v in hanlders{
(move||{
println!("Length: {:?}",v);
})();}
hanlders.push(fork{});
类似情况
#[derive(Debug)]
struct Fork;
fn main() {
let mut handlers = Vec::new();
handlers.push(Fork{});
// Make each of them think and eat 100 times
for v in handlers.iter() {
let handle = thread::spawn(move || {
for i in 0..10 {
println!("Length: {:?}", v);
};
});
}
}
会报错的原因是,for v in hanlders内部的move的确已经将所有权进行转移。for循环获取的是真实的变量。
-
所有权的转移:在这个例子中,
for v in handlers
使用了值的迭代,而不是引用。循环中的v
直接获取了handlers
中的每一个Fork
实例的所有权。每次迭代,v
是一个Fork
类型的值。 -
安全的线程捕获:当
thread::spawn
捕获变量v
时,捕获的是Fork
类型的值(所有权),而不是引用。这意味着v
不再依赖handlers
的生命周期,因此不存在生命周期的问题。Rust 的所有权系统确保了v
在线程的生命周期内是有效的,因此编译可以成功。
因此这里hanlders.push(fork{});又试图获取一个已经转移了的hanlers的所有权,所以报错。
另一个例子:
#[derive(Debug)]
struct fork{}
let mut hanlders = Vec::new();
hanlders.push(fork{});
// Make each of them think and eat 100 times
for v in hanlders.iter(){
let handle = thread::spawn(move|| {
for i in 0..10{
println!("Length: {:?}",v);
};
});
}
改成hanlders.iter(),就报错了。原因是:
-
引用的生命周期问题:
handlers.iter()
返回一个迭代器,该迭代器生成对handlers
中元素的引用。在for v in handlers.iter()
这个循环中,v
是对Fork
的一个引用 (&Fork
)。 -
thread::spawn
和'static
生命周期:当你在thread::spawn
中使用move
关键字时,闭包会捕获其环境中的变量。在这个例子中,v
被捕获为一个引用。但是,thread::spawn
创建的线程可能会在主线程结束之后继续运行,这意味着这些捕获的引用必须具有'static
生命周期,即它们需要在程序的整个生命周期内有效。然而,v
只是handlers
向量的一个短期引用,不符合'static
的要求。因此,编译器拒绝了这种用法。
改正这个问题有三个方案:
1. 想办法将局部变量的生命周期设置为static。
fn main() {
let hanlders: &'static mut Vec<fork> = Box::leak(Box::new(Vec::new()));
hanlders.push(fork {});
// Make each of them think and eat 100 times
for v in hanlders.iter() {
thread::spawn(move || {
println!("Length: {:?}", v);
});
2. 将生命周期完全给到子线程
#[derive(Debug)]
struct fork{}
let mut hanlders = Vec::new();
hanlders.push(fork{});
// Make each of them think and eat 100 times
for v in hanlders{
let handle = thread::spawn(move|| {
for i in 0..10{
println!("Length: {:?}",v);
};
});
}
3. 可以使用Mutex做局部变量,类似这样
static HANDLERS: Mutex<Vec<String>> = Mutex::new(Vec::new());