递归

优质
小牛编辑
124浏览
2023-12-01

在内部,async fn创建一个状态机类型,它包含每个子-Future,且都正处于.awaited。这使得递归async fn有点棘手,因状态机类型的结果必须包含自身:

// 这个函数:
async fn foo() {
    step_one().await;
    step_two().await;
}
// 生成了一个类型,如下:
enum Foo {
    First(StepOne),
    Second(StepTwo),
}

// 所以,这个函数:
async fn recursive() {
    recursive().await;
    recursive().await;
}

// 就生成了一个类型,如下:
enum Recursive {
    First(Recursive),
    Second(Recursive),
}

这行不通——我们创建了一个无限大的类型!编译器会抱怨:

error[E0733]: recursion in an `async fn` requires boxing
 --> src/lib.rs:1:22
  |
1 | async fn recursive() {
  |                      ^ an `async fn` cannot invoke itself directly
  |
  = note: a recursive `async fn` must be rewritten to return a boxed future.

为了搞定这一点,我们必须用Box剑走偏锋。但不幸的是,编译器的局限性意味着,仅将对recursive()的 call 包裹进Box::pin,是还不够的,我们必须将recursive变成非async函数,且它返回一个.boxed() async代码块:

use futures::future::{BoxFuture, FutureExt};

fn recursive() -> BoxFuture<'static, ()> {
    async move {
        recursive().await;
        recursive().await;
    }.boxed()
}