我正在尝试创建一个方法,该方法采用 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() -> ()函数内的条件(尽管它在作为参数传递时符合条件)。我在这里缺少什么导致这个问题,有没有办法完成我想要的东西(采用可选的闭包作为参数,如果没有提供,则使用默认函数作为闭包)?
匹配语句的所有分支必须解析为完全相同的类型。
考虑到这一点,让我们用它代表的泛型替换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()上面的方法更快,当然,如果您稍后将其存储在结构中,这将不起作用。