为什么在Rust中递归异步函数需要使用“静态参数”?

6

给定一个简单的异步函数:

async fn foo(n: usize) -> usize {
    if n > 0 { foo(n - 1).await }
    else { 0 }
}

编译器提示必须重写 async fn,使其返回一个封装的 dyn Future

| async fn foo(n: usize) -> usize {
|                           ^^^^^ recursive `async fn`
  = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`.

For more information about this error, try `rustc --explain E0733`.

编译器解释 (rustc --explain E0733):

为了实现异步递归,需要将async fn进行宏膜展开,以便将Future写入返回类型中:

use std::future::Future;
fn foo_desugared(n: usize) -> impl Future<Output = ()> {
    async move {
        if n > 0 {
            foo_desugared(n - 1).await;
        }
    }
}

最后,未来被装在一个固定的盒子里:
use std::future::Future;
use std::pin::Pin;
fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
    Box::pin(async move {
        if n > 0 {
            foo_recursive(n - 1).await;
        }
    })
}
Box<dyn Trait>确保结果具有已知大小,并且针脚需要将其保留在内存中的相同位置。


现在考虑这段代码:

fn foo(n: &usize) -> Pin<Box<dyn Future<Output = usize>>> {
    Box::pin(async move {
        if *n > 0 {
            foo(&n).await
        } else {
            0
        }
    })
}

编译器报错:变量 &n 的生命周期应该是 'static'
|   fn foo(n: &usize) -> Pin<Box<dyn Future<Output = usize>>> {
|             ------ help: add explicit lifetime `'static` to the type of `n`: `&'static usize`
| /     Box::pin(async move {
| |         if *n > 0 {
| |             foo(&n).await
| |         } else {
| |             0
| |         }
| |     })
| |______^ lifetime `'static` required

请帮助我理解正在发生的事情.

1个回答

6

Trait对象 (dyn Trait)默认具有静态生命周期,除非另有规定。因此,没有指定生命周期的盒装future和其他trait不能依赖于借用数据,除非该数据是为'static生命周期借用的(这就是你的错误信息所抱怨的内容)。

要解决这个问题,你可以明确指定生命周期,或者只使用'_',在这种情况下,它将使用n: &usize参数的省略生命周期:

//        .--  will use elided lifetime from here
//        v                      v--  give the future a non-'static lifetime
fn foo(n: &usize) -> Pin<Box<dyn '_ + Future<Output = usize>>> {
// or: fn foo<'a>(n: &'a usize) -> Pin<Box<dyn 'a + Future<Output = usize>>>
    Box::pin(async move {
        if *n > 0 {
            foo(&n).await // <-- no error, as the future lifetime now depends on the
                          //     lifetime of n instead of having a 'static lifetime
        } else {
            0
        }
    })
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接