Is it possible to send closures via channels?

后端 未结 2 1105
耶瑟儿~
耶瑟儿~ 2021-02-19 23:37

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() {         


        
2条回答
  •  故里飘歌
    2021-02-20 00:05

    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);
    }
    

提交回复
热议问题