I would like to send a closure via channels:
use std::thread;
use std::sync::mpsc;
#[derive(Debug)]
struct Test {
s1: String,
s2: String,
}
fn main() {
Yes. There are a few problems with your code.
First of all, FnOnce
is a trait, so you can't use it directly. Traits have to be either a constraint on a concrete type, or behind an indirection of some kind. Since you're sending the closure to somewhere else, you want something like Box
.
Secondly, you can't use Box
because, due to object safety rules, you can't actually call a FnOnce
through an indirection.
(As an aside, you also don't want to use FnOnce<...>
syntax, which is technically unstable; use FnOnce(...)
instead.)
To solve this, you can either switch to Fn
or FnMut
or use the not-yet-stable FnBox
trait. I've gone down this path on the basis that it probably has the semantics you want, and is likely to be stabilised in the near future. If you're uncomfortable with this, you will need to modify your closure appropriately.
The following is a joint effort between myself and Manishearth (who pointed out I'd missed the + Send
constraint):
// NOTE: Requires a nightly compiler, as of Rust 1.0.
#![feature(core)]
use std::boxed::FnBox;
use std::thread;
use std::sync::mpsc;
#[derive(Debug)]
struct Test {
s1: String,
s2: String,
}
type ClosureType = Box;
fn main() {
let t = Test { s1: "Hello".to_string(), s2: "Hello".to_string() };
let (tx, rx) = mpsc::channel::();
thread::spawn(move || {
let mut test = t;
let f = rx.recv().unwrap();
f.call_box((&mut test,));
println!("{:?}", test);
});
tx.send(Box::new(move |t: &mut Test| {
let s = "test".to_string();
t.s1 = s;
})).unwrap();
// To give the output time to show up:
thread::sleep_ms(100);
}