递归

在内部,async fn会创建一个包含了所有被.await的子Future的状态机类型。由于最终的状态机类型要包含自身,要实现递归的async fn就有些难办了:


#![allow(unused)]
fn main() {
async fn step_one() { /* ... */ }
async fn step_two() { /* ... */ }
struct StepOne;
struct StepTwo;
// 这个函数:
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()的调用包装在Box::pin还不够。我们还得将recursive转化为一个非async函数并返回一个经过.boxed()async块:


#![allow(unused)]
fn main() {
use futures::future::{BoxFuture, FutureExt};

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