除了在每个闭包之前克隆它之外,还有另一个选项可以在多个闭包中共享一个Arc吗?

时间:2015-07-11 17:43:36

标签: rust closures

我有这样的事情:

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 个答案:

答案 0 :(得分:13)

没有办法绕过它。在封闭中使用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;
        });
    }
}

答案 1 :(得分:1)

  

还有其他选择吗?

由于这种在定义闭包之前先克隆事物的模式在某种程度上很常见,所以有些人会使用proposed adding something like clone || as an analog to move ||。对于这种情况,我不会抱有希望,但是那里的许多评论指出,宏可以很好地解决这种情况。

几个板条箱提供了此宏的某种形式:

很可能许多项目都定义了自己的宏来执行类似的操作。例如,WASM example 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 };
}