无法设置默认函数关闭

R K*_*R K 0 closures rust

我正在尝试创建一个方法,该方法采用 anOption<impl Fn() -> ()>作为参数,并且,如果此参数是Some(func),则存储func为闭包,但是,如果是None,则存储一些默认函数作为闭包。具体来说,我的代码如下:

fn foo() 
{
    println!("HI");
}

fn bar(baz: Option<impl Fn () -> ()>)
{
    let func = match baz {
        Some(func) => func,
        //None => foo,
        None => unimplemented!()
    };

    func();
}

pub fn main() {
    bar(Some(foo));
}
Run Code Online (Sandbox Code Playgroud)

按原样,代码可以编译,这向我表明这foo确实应该与impl Fn () -> (). 但是,如果我用注释掉的手臂替换None我的手臂以设置为我的“默认实现”,我会收到以下错误:matchNonefoo

error[E0308]: `match` arms have incompatible types
  --> <source>:10:17
   |
6  |   fn bar(baz: Option<impl Fn () -> ()>)
   |                      ---------------- this type parameter
7  |   {
8  |       let func = match baz {
   |  ________________-
9  | |         Some(func) => func,
   | |                       ---- this is found to be of type `impl Fn() -> ()`
10 | |         None => foo,
   | |                 ^^^ expected type parameter `impl Fn() -> ()`, found fn item
11 | |         //None => unimplemented!()
12 | |     };
   | |_____- `match` arms have incompatible types
   |
   = note: expected type `impl Fn() -> ()`
           found fn item `fn() {foo}`

error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)

据我从错误中可以看出,它foo不符合impl Fn() -> ()函数内的条件(尽管它在作为参数传递时符合条件)。我在这里缺少什么导致这个问题,有没有办法完成我想要的东西(采用可选的闭包作为参数,如果没有提供,则使用默认函数作为闭包)?

cam*_*024 5

匹配语句的所有分支必须解析为完全相同的类型

考虑到这一点,让我们用它代表的泛型替换impl Fn() -> ()(这也与 BTW 相同):impl Fn()

fn bar<T>(baz: Option<T>) where T: Fn() {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

impl Trait(在函数参数中)是常规泛型的语法糖,因此这就是“编译器所看到的”。

接下来我们看一下比赛情况:

fn bar<T>(baz: Option<T>) where T: Fn() {
  let f = match baz {
    Some(f) => f,
    None => foo,
  };
}
Run Code Online (Sandbox Code Playgroud)

这是行不通的,因为 的类型foo是一种特殊的东西,称为“函数项”(本质上是唯一类型),但 的类型f是泛型参数T:它可以是任何可以想象到的类型(只要它实现Fn())。显然,这些可能不同,因此 Rust 拒绝匹配语句,因为“具有不兼容的类型”。

您正在寻找的是一个特征对象(尽管这是以堆分配和虚函数表调度为代价的):

fn bar(baz: Option<impl Fn()>) {
  let f: Box<dyn Fn()> = match baz {
    Some(f) => Box::new(f),
    None => Box::new(foo),
  };

  f();
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以立即调用该函数而不存储在变量中:

fn bar(baz: Option<impl Fn()>) {
  match baz {
    Some(f) => f(),
    None => foo(),
  };
}
Run Code Online (Sandbox Code Playgroud)

这可能比dyn Fn()上面的方法更快,当然,如果您稍后将其存储在结构中,这将不起作用。