我想创建一个类型别名来促进函数闭包,而用户不必考虑其函数的参数和返回签名。这将翻译这段代码:
async fn some_func(s: &mut Context<Props>) -> VNode {
// some function body...
}
Run Code Online (Sandbox Code Playgroud)
进入这段代码:
static SomeFunc: FC<Props> = |ctx| async {
// some function body
};
Run Code Online (Sandbox Code Playgroud)
在 JavaScript 中,这将使用 const 闭包函数定义而不是常规函数简写。
对于常规函数,这工作得很好:
type FC<T: Props> = fn(&mut Context<T>) -> Vnode;
Run Code Online (Sandbox Code Playgroud)
然后,静态闭包被提升为函数指针。
但是,impl Future不能在类型别名中使用(甚至在 1.51 nightly 上也不能使用),而且我也不能在类型别名中使用通用特征边界。我不知道这是否可能,但我很好奇是否有办法让类型别名适用于异步 fns。
我正在设计的 API 将函数作为输入(而不是结构或特征对象),我希望使其易于使用。
您不能直接执行此操作,因为每个 async fn 都有不同的返回类型,即使 future 的计算结果为相同类型。Future这是因为每个 async fn 都有其返回的唯一类型。
为此,您必须使用特征对象 ( dyn Fn) 而不是函数指针 ( fn()) 作为类型。您正在寻找的类型是
use futures::future::BoxFuture;
type FC<T> = Box<dyn Send + Sync + for<'a> Fn(&'a mut Context<T>) -> BoxFuture<'a, Vnode>>;
Run Code Online (Sandbox Code Playgroud)
上述类型将充当返回 a 的函数Future,但需要一个转换步骤才能从普通的 async fn 转换为上述类型的函数。
可以按如下方式执行此转换:
Box::new(|context| Box::pin(my_async_fn(context)))
Run Code Online (Sandbox Code Playgroud)
也可以使用 future crate 来编写。在某些情况下,使用的版本.boxed()将帮助类型检查器并避免该Box::pin版本可能给出的一些错误。
use futures::future::FutureExt;
Box::new(|context| my_async_fn(context).boxed())
Run Code Online (Sandbox Code Playgroud)
由于我们在本例中使用的特定类型别名涉及生命周期,因此无法为上述定义方便的转换。也就是说,当参数不是引用时,您可以这样做:
use futures::future::BoxFuture;
type AsyncFnPtr = Box<dyn Send + Sync + Fn(SomeArg) -> BoxFuture<'static, RetValue>>;
fn convert<F, Fut>(func: F) -> AsyncFnPtr
where
F: Send + Sync + 'static,
F: Fn(SomeArg) -> Fut,
Fut: Send + 'static,
Fut: Future<Output = RetValue>,
{
Box::new(|context| Box::pin(func(context)))
}
Run Code Online (Sandbox Code Playgroud)
其他资源: