2024/08/25
はじめに
Rustでthreadをspawnするとき、変数をmoveすることがあると思います。 その際に、moveすると、変数が移動してしまい、元のスコープで使えなくなります。
ですが、変数名を増やすことなく、元のスコープで使える方法があります。
エラーになるコード
use std::{sync::Arc, thread};
fn main() {
let x = Arc::new(10);
let t1 = thread::spawn(move || {
println!("[t1] x = {}", x);
});
let t2 = thread::spawn(move || {
println!("[t2] x = {}", x);
});
t1.join().expect("Thread panicked");
t2.join().expect("Thread panicked");
}
これをコンパイルしようとすると、以下のエラーになる。
t2
で、すでに移動済みの x
を使おうとしているためである。
error[E0382]: use of moved value: `x`
--> src/main.rs:18:28
|
4 | let x = Arc::new(10);
| - move occurs because `x` has type `Arc<i32>`, which does not implement the `Copy` trait
...
15 | let t1 = thread::spawn(move || {
| ------- value moved into closure here
16 | println!("[t1] x = {}", x);
| - variable moved due to use in closure
17 | });
18 | let t2 = thread::spawn(move || {
| ^^^^^^^ value used here after move
19 | println!("[t2] x = {}", x);
| - use occurs due to use in closure
方法1
スコープを作って、そこでmoveする。
use std::{sync::Arc, thread};
fn main() {
let x = Arc::new(10);
let t1 = thread::spawn({
let x = x.clone();
move || {
println!("[t1] x = {}", x);
}
});
let t2 = thread::spawn({
let x = x.clone();
move || {
println!("[t2] x = {}", x);
}
});
t1.join().expect("Thread panicked");
t2.join().expect("Thread panicked");
}
方法2
thread::scope
を使う。
use std::{sync::Arc, thread};
fn main() {
let x = Arc::new(10);
thread::scope(|s| {
let t1 = s.spawn(|| {
println!("[t1] x = {}", x);
});
let t2 = s.spawn(|| {
println!("[t2] x = {}", x);
});
t1.join().expect("Thread panicked");
t2.join().expect("Thread panicked");
});
}