Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

What is the diffrence between closure return by function and generated locally in rust?

The following codes show two closures: c1, c2.
c1 is returned by a function, c2 is generated locally. c1 can not be sent to a thread. Why?

fn gen_closure() -> Box<dyn Fn(&str)> {
    return Box::new(|s: &str| {
        println!("gen_closure: {}", s);
    });
}

fn main() {
    let c1 = gen_closure();
    let c2 = Box::new(|s: &str| {
        println!("main_closure: {}", s);
    });

    /* `dyn for<'r> Fn(&'r str)` cannot be sent between threads safely
    the trait `Send` is not implemented for `dyn for<'r> Fn(&'r str)`
    required because of the requirements on the impl of `Send` for `Unique<dyn for<'r> Fn(&'r str)>`
    required because it appears within the type `[closure@src/main.rs:13:24: 15:6]` */
    std::thread::spawn(move || {
        (c1)("c1");
    });

    /* This is okay */
    std::thread::spawn(move || {
        (c2)("c2");
    });
}

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

In Rust (as in e.g. C++) every closure has its own anonymous type.

Since c2 is a local, the compiler knows exactly what its concete type is, and thus can know all its traits, including that it’s Send (because it closes over nothing that’s !Send… since it’s not closing over anything).

However c1 is returned as dyn Fn, meaning as far as the compiler is concerned the only trait it can rely on is Fn. The compiler only has local visibility, and that’s what you’re telling it to rely on.

The way to make it sendable is to guaranteed that it is:

fn gen_closure() -> Box<dyn Fn(&str) + Send>

In that case, the caller can rely on this contract, and the callee will not compile if the returned function is not actually Send e.g.

fn gen_closure() -> Box<dyn Fn(&str) + Send> {
    let rc = std::rc::Rc::new(1);
    return Box::new(move |s: &str| {
        println!("gen_closure: {} {}", s, rc);
    });
}

=>

error[E0277]: `Rc<i32>` cannot be sent between threads safely
 --> src/main.rs:3:12
  |
3 |        return Box::new(move |s: &str| {
  |  _____________^________-
  | | ____________|
  | ||
4 | ||         println!("gen_closure: {} {}", s, rc);
5 | ||     });
  | ||_____-^ `Rc<i32>` cannot be sent between threads safely
  | |______|
  |        within this `[closure@src/main.rs:3:21: 5:6]`
  |
  = help: within `[closure@src/main.rs:3:21: 5:6]`, the trait `Send` is not implemented for `Rc<i32>`
  = note: required because it appears within the type `[closure@src/main.rs:3:21: 5:6]`
  = note: required for the cast to the object type `dyn for<'r> Fn(&'r str) + Send`
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading