What you are trying to do is call a closure from multiple threads. That is, share the closure across multiple threads. As soon as the phrase "share across multiple threads" crosses my mind, my first thought is to reach for Arc
(at least until RFC 458 is implemented in some form, when &
will become usable across threads).
This allows for safe shared memory (it implements Clone
without requiring its internal type to be Clone
, since Clone
just creates a new pointer to the same memory), and so you can have a single Fn
object that gets used in multiple threads, no need to duplicate it.
In summary, put your WithCall
in an Arc
and clone that.
use std::sync::Arc;
use std::thread;
type Fp = Box<Fn(i8, i8) -> i8 + Send + Sync>;
struct WithCall {
fp: Fp,
}
impl WithCall {
pub fn new(fp: Fp) -> WithCall {
WithCall { fp }
}
pub fn run(&self, a: i8, b: i8) -> i8 {
(self.fp)(a, b)
}
}
fn main() {
let adder = WithCall::new(Box::new(|a, b| a + b));
println!("{}", adder.run(1, 2));
let add_a = Arc::new(adder);
let add_b = add_a.clone();
let a = thread::spawn(move || {
println!("In remote thread: {}", add_a.run(10, 10));
});
let b = thread::spawn(move || {
println!("In remote thread: {}", add_b.run(10, 10));
});
a.join().expect("thread a panicked");
b.join().expect("thread b panicked");
}
playground
Old answer (this is still relevant): It is quite unusual to have a &mut Fn
trait object, since Fn::call
takes &self
. The mut
is not necessary, and I think it adds literally zero extra functionality. Having a &mut Box<Fn()>
does add some functionality, but it is also unusual.
If you change to a &
pointer instead of an &mut
things will work more naturally (with both &Fn
and &Box<Fn>
). Without seeing the actual code you're using, it's extremely hard to tell exactly what you're doing, but
fn call_it(f: &Fn()) {
(*f)();
(*f)();
}
fn use_closure(f: &Fn()) {
call_it(f);
call_it(f);
}
fn main() {
let x = 1i32;
use_closure(&|| println!("x is {}", x));
}
(This is partly due to &T
being Copy
and also partly due to reborrowing; it works with &mut
as well.)
Alternatively, you can close-over the closure, which likely works in more situations:
fn foo(f: &Fn()) {
something_else(|| f())
}
A FnMut
closure cannot be cloned, for obvious reasons.
There's no inherent reason a FnMut
can't be cloned, it's just a struct with some fields (and a method that takes &mut self
, rather than &self
or self
as for Fn
and FnOnce
respectively). If you create a struct and implement FnMut
manually, you can still implement Clone
for it.
Or is it safe to somehow pass a raw pointer to a Fn around, like:
let func_pnt = &mut Box<Fn<...> + Send> as *mut Box<Fn<...>>
Technically the above works, but it seems quite weird.
Technically it works if you're careful to ensure the aliasing and lifetime requirements of Rust are satisfied... but by opting in to unsafe pointers you're putting that burden on yourself, not letting the compiler help you. It is relatively rare that the correct response to a compiler error is to use unsafe
code, rather than delving in to the error and tweaking the code to make it make more sense (to the compiler, which often results in it making more sense to humans).