Есть ли другой вариант делить Арку в нескольких замыканиях, кроме клонирования перед каждым закрытием?
У меня есть что-то вроде этого:
use std::sync::Arc;
fn main() {
let arc = Arc::new(42);
move || { arc.clone() };
move || { arc.clone() };
}
Я получаю:
error[E0382]: capture of moved value: `arc`
--> src/main.rs:6:19
|
5 | move || { arc.clone() };
| ------- value moved (into closure) here
6 | move || { arc.clone() };
| ^^^ value captured here after move
|
= note: move occurs because `arc` has type `std::sync::Arc<i32>`, which does not implement the `Copy` trait
Я понимаю, почему я получаю это: clone
не вызывается раньше arc
передается на закрытие. Я могу исправить это, определив каждое замыкание в функции и клонировать Arc
перед передачей в закрытие, но есть ли другой вариант?
2 ответа
Обойти это невозможно. Вы должны клонировать Arc
прежде чем он будет использован в закрытии. Общий шаблон заключается в том, чтобы повторно связать клонированный Arc
с тем же именем во вложенной области видимости:
use std::sync::Arc;
fn main() {
let arc = Arc::new(42);
{
let arc = arc.clone();
move || { /* do something with arc */ };
}
{
let arc = arc.clone();
move || { /* do something else with arc */ };
}
}
Обычно это делается вместе с thread::spawn()
:
use std::sync::{Arc, Mutex};
use std::thread;
const NUM_THREADS: usize = 4;
fn main() {
let arc = Arc::new(Mutex::new(42));
for _ in 0..NUM_THREADS {
let arc = arc.clone();
thread::spawn(move || {
let mut shared_data = arc.lock().unwrap();
*shared_data += 1;
});
}
}
есть ли другой вариант?
Поскольку эта модель клонирования вещей до определения замыкания является довольно распространенной, некоторые люди предлагают добавить что-то вроде clone ||
как аналог move ||
, Я бы не стал надеяться на это, но в ряде комментариев указывалось, что макросы могут решить проблему достаточно хорошо.
Несколько ящиков предоставляют некоторую форму этого макроса:
Вполне вероятно, что многие проекты определяют свои собственные макросы, чтобы сделать что-то подобное. Например, пример WASM rust-todomvc определяет:
macro_rules! enclose {
( ($( $x:ident ),*) $y:expr ) => {
{
$(let $x = $x.clone();)*
$y
}
};
}
Который может быть использован как:
fn main() {
let arc = Arc::new(42);
enclose! { (arc) move || arc };
enclose! { (arc) move || arc };
}