如何定义一个在没有 where 子句的情况下接收异步闭包作为参数的函数

Ken*_*eth 4 asynchronous where-clause rust

当尝试编写一个接收异步闭包的函数时,我发现它有点棘手。

我知道正确的版本是

pub async fn f1<F, Fut>(f: F) -> u32
where
    F: Fn(u32) -> Fut,
    Fut: Future<Output = u32>,
{
    f(9u32).await
}
Run Code Online (Sandbox Code Playgroud)

然而,whereRust 文档中的子句说这只是表达这些类型的一种便捷方式,所以我尝试删除 where 子句,如下所示:

pub async fn f2(f: Fn(u32) -> Future<Output = u32>) -> u32 {
    f(9u32).await
}
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,Rust 拒绝编译它,说

error: trait objects must include the dyn keyword
Run Code Online (Sandbox Code Playgroud)

有人知道删除该where条款的正确方法是什么吗?

这个子句在这里发挥了什么魔力where

rod*_*igo 5

在你的第一个片段中,你必须限制:

  • F必须执行Fn(u32) -> Fut
  • Fut必须执行Future<Output = u32>

但在你的第二个片段中没有任何限制。内联约束的语法使用关键字impl

pub async fn f2(f: impl Fn(u32) -> Future<Output = u32>) -> u32 {
    f(9u32).await
}
Run Code Online (Sandbox Code Playgroud)

这也不起作用,因为仅impl适用于Fn特征,而不适用于返回特征,因此编译器抱怨不允许使用裸特征,您应该添加dyn到它。

不好的建议,因为:

pub async fn f2(f: impl Fn(u32) -> dyn Future<Output = u32>) -> u32 {
    f(9u32).await
}
Run Code Online (Sandbox Code Playgroud)

也不起作用,因为dyn Trait类型未调整大小且无法返回。

您可以在那里尝试另一个impl,通常适用于返回类型,但是:

pub async fn f2(f: impl Fn(u32) -> impl Future<Output = u32>) -> u32 {
    f(9u32).await
}
Run Code Online (Sandbox Code Playgroud)

函数和方法返回类型之外不允许使用 impl Trait`

我所知道的限制特征返回类型的唯一语法Fn是以下where语法:

pub async fn f2<Fut>(f: impl Fn(u32) -> Fut) -> u32
where
    Fut: Future<Output = u32>,
{
    f(9u32).await
}
Run Code Online (Sandbox Code Playgroud)

但现在您处于完整where模式,我认为没有理由保留内联约束。就我个人而言,我认为在同一函数上使用两种语法是不好的风格。