函数返回的闭包和 Rust 本地生成的闭包有什么区别?

Pro*_*ter 5 closures rust

以下代码显示了两个闭包:c1、c2。c1由函数返回,c2在本地生成。c1 无法发送到线程。为什么?

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");
    });
}
Run Code Online (Sandbox Code Playgroud)

Mas*_*inn 9

在 Rust 中(例如 C++),每个闭包都有自己的匿名类型。

由于c2是本地的,编译器确切地知道它的概念类型是什么,因此可以知道它的所有特征,包括它的特征Send(因为它不会关闭任何东西!Send……因为它不会关闭任何东西)。

然而c1返回为dyn Fn,这意味着就编译器而言,它可以依赖的唯一特征是Fn。编译器仅具有本地可见性,这就是您告诉它所依赖的。

使其可发送的方法是断言并保证它是:

fn gen_closure() -> Box<dyn Fn(&str) + Send>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,调用者可以依赖这个契约,并且如果返回的函数实际上不是,则被调用者将不会编译,Send例如

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);
    });
}
Run Code Online (Sandbox Code Playgroud)

=>

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`
Run Code Online (Sandbox Code Playgroud)