如何等待盒装未来的结果?

How can one await a result of a boxed future?

use futures::{future, Future};

fn test() -> Box<dyn Future<Output = bool>> {
    Box::new(future::ok::<bool>(true))
}

async fn async_fn() -> bool {
    let result: bool = test().await;
    return result;
}

fn main(){
    async_fn();
    println!("Hello!");
}

Playground

错误:

error[E0277]: the trait bound `dyn core::future::future::Future<Output = bool>: std::marker::Unpin` is not satisfied
  --> src/main.rs:8:24
   |
8  |     let result: bool = test().await;
   |                        ^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn core::future::future::Future<Output = bool>`
   |
   = note: required because of the requirements on the impl of `core::future::future::Future` for `std::boxed::Box<dyn core::future::future::Future<Output = bool>>`

当谈到 Boxfuture 时,使用 Box::pin instead of Box::new:

几乎总是有意义的
use std::pin::Pin;
use futures::{future, Future};

fn test() -> Pin<Box<dyn Future<Output = Result<bool, ()>>>> {
    Box::pin(future::ok(true))
}

async fn async_fn() -> bool {
    test().await.unwrap()
}

这个原因很有意思。 Pin 有一个 blanket implementation for Unpin:

impl<P> Unpin for Pin<P> where
    P: Unpin,

里面的Box<T>unconditionally Unpin:

impl<T> Unpin for Box<T> where
    T: ?Sized,

所以 Pin<Box<dyn Future>> 是未固定的 Future。一切正常,但为什么 Box 本身没有?这是 Deref 阻碍的地方:

impl<T: ?Sized> Deref for Box<T> {
    type Target = T;
}

await 需要未固定的 Future,而您使用 Box::new 创建的 Box<dyn Future> 确实包含 Future。所以它被自动取消引用并且 Unpin 丢失,除非你用 Box<dyn Future + Unpin>.

明确声明它

编辑:@ÖmerErden 关于 Box<dyn Future> 不起作用的原因是正确的。

根据the implementation

impl<F> Future for Box<F>
where
    F: Unpin + Future + ?Sized, 

盒装期货仅在 Box 内的期货实施 Unpin.

时实施 Future 特征

由于您的函数不保证 returned 未来实现 Unpin,因此您的 return 值将被视为未实现 Future。你不能 await 因为你的类型基本上不是 Future.

来自@Stargateur 的解决方案,向签名添加显式类型边界,有效 (Playground):

fn test() -> Box<dyn Future<Output = Result<bool, ()>> + Unpin> 

如果您使用的是 futures-rs,则有一个辅助类型 BoxFuture。您可以使用 BoxedFuture 而无需明确说明 Unpin:

use futures::future::BoxFuture;

fn test() -> BoxFuture<'static, Result<bool, ()>> {
    Box::pin(async { Ok(true) })
}

Playground