我正在尝试编写一个需要一部分函数的函数。考虑以下简单的illustration:
fn g<P: Fn(&str) -> usize>(ps: &[P]) { }
fn f1() -> impl Fn(&str) -> usize { |s: &str| s.len() }
fn f2() -> impl Fn(&str) -> usize { |s: &str| s.len() }
fn main() {
g(&[f1(), f2()][..]);
}
无法编译:
error[E0308]: mismatched types
--> src/main.rs:6:15
|
6 | g(&[f1(), f2()][..]);
| ^^^^ expected opaque type, found a different opaque type
|
= note: expected type `impl for<'r> std::ops::Fn<(&'r str,)>` (opaque type)
found type `impl for<'r> std::ops::Fn<(&'r str,)>` (opaque type)
有什么办法吗?
答案 0 :(得分:3)
您的问题是数组的每个元素都必须具有相同的类型,但是声明为返回impl Trait
的函数的返回是不透明类型,这是未指定的,未命名类型,只能通过给定特征使用。
您有两个函数返回相同的impl Trait
,但这并不意味着它们返回相同的类型。实际上,如编译器所示,它们是不同的不透明类型,因此它们不能属于同一数组。如果要编写一个具有相同类型的值的数组,例如:
g(&[f1(), f1(), f1()]);
然后它会工作。但是功能不同,类型也会不同,无法构建数组。
这是否意味着您的问题没有解决方案?当然不是!您只需要调用动态调度即可。那就是您必须使切片类型为&[&dyn Fn(&str) -> usize]
。为此,您需要做两件事:
&dyn Trait
或Box<dyn Trait>
而非Trait
)进行。&dyn Trait
进行显式转换,以避免转换过程中出现歧义。有很多方法可以进行转换:可以转换数组的第一个元素,也可以声明临时变量,或为切片指定类型。我更喜欢后者,因为它更加对称。像这样:
fn main() {
let fns: &[&dyn Fn(&str) -> usize] =
&[&f1(), &f2()];
g(fns);
}
使用此解决方案链接到playground。