递归异步函数中的函数参数

时间:2020-06-07 12:59:17

标签: rust async-await

在Rust中,异步函数中可以具有函数参数:

use futures::executor::block_on;

async fn hello_world(cb: &dyn Fn() -> u32) {
    println!("hello, world! {}", cb());
}

fn main() {
    let future = hello_world(&|| { 42 } );
    block_on(future);
}

但是这些异步函数的限制之一是它们不能递归。文献建议使用BoxFuture之类的方法来解决此问题。但是,如果有一个函数参数,则记录的简单转换将不起作用:

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

fn hello_world(cb: &dyn Fn() -> u32) -> BoxFuture<'static, ()> {
    async move {
        println!("hello, world! {}", cb());
    }.boxed()
}

fn main() {
    let future = hello_world(&|| { 42 } );
    block_on(future);
}
error[E0277]: `dyn std::ops::Fn() -> u32` cannot be shared between threads safely
 --> src/main.rs:7:7
  |
7 |     }.boxed()
  |       ^^^^^ `dyn std::ops::Fn() -> u32` cannot be shared between threads safely
  |
  = help: the trait `std::marker::Sync` is not implemented for `dyn std::ops::Fn() -> u32`
  = note: required because of the requirements on the impl of `std::marker::Send` for `&dyn std::ops::Fn() -> u32`
  = note: required because it appears within the type `[static generator@src/main.rs:5:16: 7:6 cb:&dyn std::ops::Fn() -> u32 _]`
  = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@src/main.rs:5:16: 7:6 cb:&dyn std::ops::Fn() -> u32 _]>`
  = note: required because it appears within the type `impl core::future::future::Future`

error: aborting due to previous error

为什么用BoxFuture进行转换会导致编译错误? 如何在递归异步函数中具有函数参数?

我尝试使用LocalBoxFuture代替BoxFuture,但错误仍然存​​在。

2 个答案:

答案 0 :(得分:0)

似乎您需要进一步限制传递给hello_world的函数-确保它既是Send又是Sync,以便可以在线程之间安全地共享。

我在期货或异步Rust方面没有做很多工作-因此我对细节不完全了解。但是根据错误消息,我可以通过简单地添加这些约束并让Rust推断生命周期而不是使用'static来使您的示例编译:

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

fn hello_world<F: Send + Sync + Fn() -> u32>(cb: &F) -> BoxFuture<'_, ()> {
    async move {
        println!("hello, world! {}", cb());
    }
    .boxed()
}

fn main() {
    let future = hello_world(&|| 42);
    block_on(future);
}

Playground Link

答案 1 :(得分:0)

我还发现了这个条板箱https://github.com/dcchut/async-recursion对我有用。