您如何通过采用 &mut self 的方法对存储在结构中的 Future 调用 future::select?

How do you call future::select on a Future stored in a struct from a method that takes &mut self?

我想将我们偶尔等待的未来存储在结构中。我的用例是有一个信号告诉我的网络数据包处理程序正常关闭。一个最小的例子可能看起来像这样,依赖于期货 0.3:

use futures::{
    executor::block_on,
    future::{pending, select, Either, Future},
}; // 0.3.4

struct Foo<F: Future + Unpin> {
    fut: F,
    fut_opt: Option<F>,
}

impl<F: Future + Unpin> Foo<F> {
    async fn wait(self: &mut Self) {
        let bar = pending::<&str>();
        match select(self.fut, bar).await {
            Either::Left(_) => println!("foo"),
            Either::Right(_) => println!("bar"),
        }
    }

    async fn wait_optional(self: &mut Self) {
        let bar = pending::<&str>();
        if let Some(foo) = self.fut_opt.take() {
            match select(foo, bar).await {
                Either::Left(_) => println!("foo"),
                Either::Right((_, foo_fut)) => {
                    self.fut_opt.replace(foo_fut);
                    println!("bar")
                }
            }
        }
    }
}

fn main() {
    let mut foo = Foo {
        fut: pending::<()>(),
        fut_opt: Option::from(pending::<()>()),
    };

    block_on(foo.wait())
}

问题是 select 想要移动 fn wait(..) 版本中的值,所以我遇到编译错误:

error[E0507]: cannot move out of `self.fut` which is behind a mutable reference
  --> src/main.rs:14:22
   |
14 |         match select(self.fut, bar).await {
   |                      ^^^^^^^^ move occurs because `self.fut` has type `F`, which does not implement the `Copy` trait

可以在 fn wait_optional 中看到我想出的解决方法:我正在(ab)使用 Option 来存储未来,需要时将其取出然后放回原处作为 select returns Either 未曾期待的未来。这编译并且似乎工作得很好 - 但感觉很糟糕。有没有 "proper" 方法来实现这个目标?

对未来进行可变引用:

use futures::{
    executor::block_on,
    future::{pending, select, Either, Future},
}; // 0.3.4

struct Foo<F: Future + Unpin> {
    fut: F,
}

impl<F: Future + Unpin> Foo<F> {
    async fn wait(&mut self) {
        let bar = pending::<&str>();
        match select(&mut self.fut, bar).await {
            Either::Left(_) => println!("foo"),
            Either::Right(_) => println!("bar"),
        }
    }
}

fn main() {
    let mut foo = Foo {
        fut: pending::<()>(),
    };

    block_on(foo.wait())
}

这是因为 Futureimplemented for any mutable reference to a Future 但有某些限制:

impl<'_, F> Future for &'_ mut F
where
    F: Unpin + Future + ?Sized, 

另请参阅:

  • Using the same iterator multiple times in Rust
  • Temporarily move out of borrowed content