3

I'm trying to write a closure that uses an Arc by cloning it. Ideally I'd like to have the clone inside the closure, but I'm kinda forced to pass the original Arc, which might be the reason I'm getting the error:

use std::sync::Arc;
use std::sync::Condvar;
use std::sync::Mutex;
use std::collections::VecDeque;

type Fifo<T> = Arc<(Mutex<VecDeque<T>>, Condvar)>;

fn executor(f: Box<dyn Fn()>) {
    f();
}

fn main() {
    let a = Fifo::<u8>::new(
        (Mutex::new(VecDeque::new()), Condvar::new())
    );
    
    let r = Box::new(||{
        let f = a.clone();
        f.0.lock().unwrap().push_back(0);
    });
    executor(r);
}

Error:

error[E0597]: `a` does not live long enough
  --> src/main.rs:19:17
   |
18 |     let r = Box::new(||{
   |                      -- value captured here
19 |         let f = a.clone();
   |                 ^ borrowed value does not live long enough
...
22 |     executor(r);
   |              - cast requires that `a` is borrowed for `'static`
23 | }
   | - `a` dropped here while still borrowed

error: aborting due to previous error

I thought changing to

let r = Box::new(||{
    //let f = a.clone();
    a.0.lock().unwrap().push_back(0);
});

would force the closure to decide to clone a, therefore fixing the problem, but I get the same error.

How can I pass an Arc to a closure?

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • 1
    Clone the Arc _outside_ the closure, and use a `move` closure to force the move: `let r = { let a = a.clone(); Box::new(move || { a.0.lock().unwrap().push_back(0); }) };` Also note that Rust never decides to clone values automatically, in contrast to C++. A closure can automatically decide whether to capture by move or reference, and since you don't consume the captured value, it decided on reference, which we had to override with the `move` keyword. – user4815162342 Sep 26 '20 at 07:07

1 Answers1

4

Clone the Arc outside the closure and then move the clone into the closure. Example:

use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::Condvar;
use std::sync::Mutex;

type Fifo<T> = Arc<(Mutex<VecDeque<T>>, Condvar)>;

fn executor(f: Box<dyn Fn()>) {
    f();
}

fn main() {
    let a = Fifo::<u8>::new((Mutex::new(VecDeque::new()), Condvar::new()));

    let f = a.clone();
    let r = Box::new(move || {
        f.0.lock().unwrap().push_back(0);
    });

    executor(r);
}

playground

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98