rust - 为什么递归异步函数在 Rust 中需要“静态参数”?
问题描述
给定一个简单的异步函数:
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<...>
确保了结果的大小是已知的,并且需要 pin 将其保存在内存中的相同位置。
现在考虑这段代码:
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
请帮助我了解发生了什么。
解决方案
除非另有说明,否则特征对象 ( dyn 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
}
})
}
推荐阅读
- php - 产品类别网格中的随机间隙(WooCommerce)
- flutter - 如何从 Flutter 中的 Firestore 文档中获取文档 ID?
- javascript - Google Places 仅在搜索字段中获取街道地址
- c# - 从 Asset Bundle 中加载资源以在 Unity 中进行 Play 资源交付
- python - 自动化无聊的东西 - 第 4 章:硬币翻转解决方案
- node.js - 在 NPM 上发布要包含在 README.md 中的图像
- angular - 将 mat-chip 的点击事件传递给 mat-autocomplete 中的父 mat-option
- react-native - 如何使用 expo-file-system 检查文件是否存在?
- graphql - 我如何在 apollo server express 中启用@defer 指令
- compiler-errors - 没有延迟形状的数组出错