为什么将闭包传递给接受函数指针的函数不起作用?

时间:2018-10-08 06:56:27

标签: rust

second edition of The Rust Programming Language中(重点是我):

  

函数指针实现了所有三个闭包特征(FnFnMutFnOnce),因此您始终可以将函数指针作为函数的参数传递将会关闭。最好使用泛型类型和闭包特征之一编写函数,以便您的函数可以接受函数或闭包。

将闭包传递给接受函数指针作为参数的函数不会编译:

fn main() {
    let a = String::from("abc");

    let x = || println!("{}", a);

    fn wrap(c: fn() -> ()) -> () {
        c()
    }

    wrap(x);
}
error[E0308]: mismatched types
  --> src/main.rs:10:10
   |
10 |     wrap(x);
   |          ^ expected fn pointer, found closure
   |
   = note: expected type `fn()`
              found type `[closure@src/main.rs:4:13: 4:33 a:_]`

为什么这不起作用?

2 个答案:

答案 0 :(得分:8)

闭包不是函数。

您可以将一个函数传递给需要关闭的函数,但是没有理由相反。

如果您希望能够同时传递闭包和函数作为参数,则只需为闭包做准备即可。

例如:

let a = String::from("abc");

let x = || println!("x {}", a);

fn y() {
    println!("y")
}

fn wrap(c: impl Fn()) {
    c()
}

wrap(x); // pass a closure
wrap(y); // pass a function

答案 1 :(得分:5)

在某些情况下,您可以将闭包作为函数指针传递。这有效:

fn main() {
    let x = || {
        let a = String::from("abc");
        println!("{}", a);
    };

    fn wrap(c: fn()) {
        c()
    }

    wrap(x);
}

重要的区别是,不允许闭包从其环境中捕获任何东西。这意味着我们必须防止String越过闭合边界。

任何不捕获环境的闭包都可以被简单地重写为匿名独立函数,然后转换为函数指针。

添加环境后,该环境将不再可转换,并且the existing answer中的所有内容都将适用。

请注意,说明-> ()是非惯用语,因为如果未指定任何内容,这是默认设置。

另请参阅: