当前位置: 首页 > 知识库问答 >
问题:

为什么递归异步函数需要Rust中的静态参数?

潘佐
2023-03-14

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

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

编译器抱怨说< code>async fn必须重写才能返回装箱的< code>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--在解释E0733):

要实现异步递归,需要对异步 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;
        }
    })
}

盒子

现在考虑以下代码:

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

编译器抱怨

|   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个答案

锺离卓
2023-03-14

默认情况下,Trait 对象 (dyn Trait) 将具有静态生存期,除非另有指定。因此,没有指定生存期的盒装期货(和其他特征)不能依赖于借用的数据,除非在“静态生存期”中借用了该数据。(这是您的错误消息所抱怨的)。

要解决此问题,您可以显式指定生存期,也可以只使用“_,在这种情况下,它将使用n的省略生存期:

//        .--  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
        }
    })
}

 类似资料:
  • 谁能告诉我为什么函数参数不能是?这是函数参数在上声明并在函数返回时被取消分配的原因吗?没有办法保留参数值?只是糊涂了。请澄清。 多谢了。

  • 问题内容: 我有一个异步函数,要连续多次调用。问题是“多个”可以是几十万或数百万… 显而易见的方法是从回调中调用相同的函数,如下所示: 当然,涉及一些逻辑来停止递归。问题是堆栈是否充满了调用,并可能在某些时候导致堆栈溢出? 问题答案: 问题是堆栈是否充满了调用,并可能在某些时候导致堆栈溢出? 否。 如果调用回调是异步传递的,则不会堆积堆栈。 在您的代码中: 这是逐步发生的事情: 首先被称为。 然后

  • 问题内容: 必须使用无参数构造函数(像Hibernate这样的工具会在此构造函数上使用反射来实例化对象)。 我得到了这个手挥手的答案,但是有人可以进一步解释吗?谢谢 问题答案: hibernate,并且通常通过反射创建对象的代码用于创建类的新实例。此方法需要一个公共的无参数构造函数才能实例化该对象。对于大多数用例,提供无参数构造函数不是问题。 有一些基于序列化的技巧可以解决没有no-arg构造函数

  • 在§13.3.1/4(N3337)中,您会发现以下内容: 对于静态成员函数,隐式对象参数被认为与任何对象匹配(因为如果选择了函数,则丢弃对象)。 §9.4.1/2有这样一种说法: 静态成员函数没有this指针。 那么,静态成员函数的隐式对象参数的用途是什么?

  • 问题内容: 我在课堂上有这个功能: 我尝试使用此函数来调用该函数: 问题是编译器希望它看起来像这样: 为什么第一个会导致错误? 问题答案: Swift 2.0更新 :现在,默认情况下,函数的功能与方法相同,并且对于两种方法而言: 第一个参数没有外部名称;和 其他参数的外部名称与内部名称相同。 除此之外,下面的规则仍然适用,只是速记语法已消失。 这是一个更一般的答案:函数在类之外定义为真函数时以及在