function - How to write a function that takes a slice of functions?
问题描述
I am trying to write a function that takes a slice of functions. Consider the following simple 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()][..]);
}
It fails to compile:
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)
Is there any way to do this?
解决方案
Your problem is that every element of the array must be of the same type, but the return of a function declared as returning impl Trait
is an opaque type, that is an unspecified, unnamed type, that you can only use by means of the given trait.
You have two functions that return the same impl Trait
but that does not mean that they return the same type. In fact, as your compiler shows, they are different opaque types, so they cannot be part of the same array. If you were to write an array of values of the same type, such as:
g(&[f1(), f1(), f1()]);
then it would work. But with different functions, there will be different types and the array is impossible to build.
Does that mean there is no solution for your problem? Of course not! You just have to invoke dynamic dispatch. That is you have to make your slice of type &[&dyn Fn(&str) -> usize]
. For that you need to do two things:
- Add a level of indirection: dynamic dispatching is always done via references or pointers (
&dyn Trait
orBox<dyn Trait>
instead ofTrait
). - Do an explicit cast to the
&dyn Trait
to avoid ambiguities in the conversion.
There are many ways to do the cast: you can cast the first element of the array, or you can declare the temporary variables, or give the slice a type. I prefer the latter, because it is more symmetric. Something like this:
fn main() {
let fns: &[&dyn Fn(&str) -> usize] =
&[&f1(), &f2()];
g(fns);
}
Link to a playground with this solution.
推荐阅读
- python - 如何将以下 json 文件转换为数据框?
- linux - 如何在 bash 中将我的 .txt 文件转换为 .json?
- python - 如何找到列表中增加总价值的最少项目数
- jenkins - Jenkins MultiBranchPipeline 首先加载共享库 repo
- html - 如何创建 Excel 文件下载链接
- javascript - JavaScript:函数返回一个基于回调函数结果重新排序的数组
- reactjs - 如何在没有 Node 的情况下正确声明 React 和 Require 的模块?
- c# - BLE 扫描间隔 Windows 10 - DeviceIoControl 返回 false,最后一个错误:1784 - ERROR_INVALID_USER_BUFFER
- azure - 即使打开了自动交换,Azure 函数部署也会导致短暂的 503 错误
- flutter - 为什么 Dart 在某些可以从函数签名中确定的情况下不推断参数类型?