Poperton
Poperton

Reputation: 2148

How to pass an Arc clone to a closure?

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?

Upvotes: 4

Views: 2131

Answers (1)

pretzelhammer
pretzelhammer

Reputation: 15115

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

Upvotes: 4

Related Questions