Is there a way to have a Rust closure that moves only some variables into it?
Yes, it is possible to move only one or some variables into a closure (rather than all or none).
Yes, this can be used to "circumvent" reference counting.
I found an answer in the documentation of rayon::scope
that turns out to be exactly about this problem: 'Accessing the stack data [from within a scoped threads scope]'. That page also has an example that is clearer than the pseudocode in this question.
It turns out that you can either:
Use a
move
closure but refer to variables in the outer scope by shadowing them with a reference, therefore capturing them by reference rather than by value, usinglet settings = &settings
:crossbeam::scope(|scope| { let settings = &settings; // refer to outer variable by reference for score in 0..MAX_FEASIBLE_SCORE { scope.spawn(move |_| { let work_result = do_cool_computation(settings, score); println!("{:?}", work_result); }); } }) .unwrap();
Use a normal closure, and only move the required variables by shadowing them inside the closure using
let score = score
:crossbeam::scope(|scope| { for score in 0..MAX_FEASIBLE_SCORE { scope.spawn(|_| { let score = score; // capture only score let work_result = do_cool_computation(&settings, score); println!("{:?}", work_result); }); } }) .unwrap();
The closure! macro gives the ability to selectively reference, move, or clone variables into a closure.
Example taken from the docs:
use closure::closure;
let string = "move".to_string();
let x = 10;
let mut y = 20;
let rc = Rc::new(5);
let closure = closure!(move string, ref x, ref mut y, clone rc, |arg: i32| {
...
});
Variables that are captured but not listed default to being moved.