rust - 如何包装一个返回 Future 的闭包,而不是同步?

标签 rust rust-tokio

我有以下代码,试图包装一个返回 future 的函数:

use std::future::Future;
use std::pin::Pin;

pub type BoxedOperation = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + 'static>;

fn create_func<L, R>(func: L) -> BoxedOperation
where L: Fn() -> R + Clone + Send + 'static,
      R: Future<Output = ()> + Send + 'static
{
    Box::new(move || {
        let func = func.clone();
        Box::pin(async move {
            // My logic before
            (func)().await; // In the future, func will receive params
            // my logic after
        })
    })
}

此代码无法编译-

  --> src/main.rs:14:9
   |
14 | /         Box::pin(async move {
15 | |             (func)().await;
16 | |         })
   | |__________^ future created by async block is not `Send`
   |
note: future is not `Send` as this value is used across an await
  --> src/main.rs:15:21
   |
15 |             (func)().await;
   |             ------  ^^^^^^ await occurs here, with `(func)` maybe used later
   |             |
   |             has type `&L` which is not `Send`
note: `(func)` is later dropped here
  --> src/main.rs:15:27
   |
15 |             (func)().await;
   |                           ^
help: consider moving this into a `let` binding to create a shorter lived borrow
  --> src/main.rs:15:13
   |
15 |             (func)().await;
   |             ^^^^^^^^
   = note: required for the cast from `impl Future<Output = ()>` to the object type `dyn Future<Output = ()> + Send`
help: consider further restricting this bound
   |
9  | where L: Fn() -> R + Clone + Send + 'static + std::marker::Sync,
   |   
                                          +++++++++++++++++++

现在,这里的 BoxedOperation 返回一个 Send 的 future 至关重要,这样我以后就可以 tokio::spawn 它,但我也不想要它同步,因为这需要 func 中使用的所有内容也都同步。我真的不明白为什么这不是首先发送。

最佳答案

这是一个棘手的案例。

当您调用func时,编译器使用Fn::call()通过引用来获取 self 。因此编译器借用了func,创建了&L,并调用了这个类型。但如 generator/async functions captures are not precise ,这种类型最终会被包含在生成的 future 中,即使不需要它,因此生成的 future 需要 &L: Send -> L: Sync 才能发送

要解决此问题,您可以强制编译器在等待返回的 future 之前立即删除借用:

fn create_func<L, R>(func: L) -> BoxedOperation
where
    L: Fn() -> R + Clone + Send + 'static,
    R: Future<Output = ()> + Send + 'static,
{
    Box::new(move || {
        let func = func.clone();
        Box::pin(async move {
            let fut = { func() }; // Notice the block.
            fut.await;
        })
    })
}

关于rust - 如何包装一个返回 Future 的闭包,而不是同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74920440/

相关文章:

mongodb - 使用 mongodb-1.2.2 和 Rocket-0.5.0-rc.1 时如何解决异步不兼容问题?

rust - 在 actix-web 服务器和异步闭包之间共享状态

linux - TcpStream 上的 std::io::BufReader 会导致数据丢失吗?

rust - 为什么 BufReader 实际上不会缓冲短查找?

rust - 列表中相同索引项的并行迭代 |语法问题

rust - 无法返回对lazy_static HashMap中元素的引用,因为它的生存时间不够长

rust - 无法移出可变引用后面的 ***

rust - 什么是 futures::future::lazy?

websocket - tokio_tungstenite::WebSocketStream 的 split() 方法在哪里实现?

windows - 无法在 Windows 上使用 Rust 和 GTK 运行 pkg-config