我试图产生几个新线程,每个线程都有自己的某个状态的副本。我想要的是这个:
use std::thread;
fn main() {
let data = vec![42; 10];
let more_data = "Important data".to_string();
for _ in 1..=4 {
thread::spawn(|| foo(data.clone(), more_data.clone()));
}
}
fn foo(_data: Vec<u64>, _more_data: String) {}
这不能编译,因为克隆是在新线程上完成的,这可能比主线程更长。很公平,但似乎没有好的方法告诉Rust在主线程上执行克隆,然后然后将所有权移动到新线程。每当我遇到这个问题时,我最终会这样做:
use std::thread;
fn main() {
let data = vec![42; 10];
let more_data = "Important data".to_string();
for _ in 1..=4 {
let cloned_data = data.clone();
let cloned_more_data = more_data.clone();
thread::spawn(move || foo(cloned_data, cloned_more_data));
}
}
fn foo(_data: Vec<u64>, _more_data: String) {}
它做了我想要的,但它非常嘈杂和样板,特别是有很多争论。还有更好的方法吗?
答案 0 :(得分:2)
有更好的方法吗?
不,不使用标准库。这有a proto-RFC about supporting some syntax,但这远远没有发生。它确实有多种解决方案供您今天使用,例如enclose
macro
macro_rules! enclose {
( ($( $x:ident ),*) $y:expr ) => {
{
$(let $x = $x.clone();)*
$y
}
};
}
这允许您编写如下代码:
enclose!((data, more_data) {
thread::spawn(move || foo(data, more_data));
})
答案 1 :(得分:2)
您可以使用iter::repeat()
为您克隆数据:
use std::thread;
fn main() {
let data = vec![42; 10];
let more_data = "Important data".to_string();
let threads: Vec<_> = std::iter::repeat((data, more_data))
.take(5)
.map(|(data, more_data)| thread::spawn(|| foo(data, more_data)))
.collect();
let result: Vec<_> = threads.into_iter().map(|x| x.join()).collect();
result.iter().for_each(|x| {
println!("{:?}", x);
});
}
fn foo(_data: Vec<u64>, _more_data: String) -> u64 {
println!("Hello");
42
}