I would like to send commands (closures) to different threads, with the closure capturing a non-Sync
variable (therefore I cannot "share" the closure with an Arc
, as explained in Can you clone a closure?).
The closure only captures elements which implement Clone
, so I would feel that the closure could derive Clone
as well.
#![feature(fnbox)]
use std::boxed::FnBox;
use std::sync::mpsc::{self, Sender};
use std::thread;
type Command = Box<FnBox(&mut SenderWrapper) + Send>;
struct SenderWrapper {
tx: Option<Sender<u64>>,
}
impl SenderWrapper {
fn new() -> SenderWrapper {
SenderWrapper { tx: None }
}
}
fn main() {
let (responses_tx, responses_rx) = mpsc::channel();
let closure: Command = Box::new(move |snd: &mut SenderWrapper| {
snd.tx = Some(responses_tx); // Captures tx, which is not Sync but is Clone
});
let mut commands = Vec::new();
for i in 0..2i32 {
let (commands_tx, commands_rx) = mpsc::channel();
commands.push(commands_tx);
thread::spawn(move || {
let mut wrapper = SenderWrapper::new();
let command: Command = commands_rx.recv().unwrap();
command.call_box((&mut wrapper,));
// Continue ...
});
}
for tx in commands.iter() {
commands[0].send(closure.clone()).unwrap(); // How can I make this clone() work?
}
// use answers ...
}
error[E0599]: no method named `clone` found for type `std::boxed::Box<for<'r> std::boxed::FnBox<(&'r mut SenderWrapper,), Output=()> + 'static>` in the current scope
--> src/main.rs:40:34
|
40 | commands[0].send(closure.clone()).unwrap();
| ^^^^^
|
= note: the method `clone` exists but the following trait bounds were not satisfied:
`std::boxed::Box<for<'r> std::boxed::FnBox<(&'r mut SenderWrapper,), Output=()>> : std::clone::Clone`
Is there any way in the current syntax where we can implement / derive traits for closures?
A dirty workaround for this would be to define (by hand) a structure containing the required environment, implement Clone
, and define the FnOnce
or Invoke
trait.