首页 > 解决方案 > 试图修改 Rc 内的期货 Vec>

问题描述

我尝试等待并从期货中删除一个接一个Vec的未来。这没用。我明白为什么它不起作用:Pin不可复制。但是如何纠正这个错误呢?

extern crate futures;
use std::cell::{RefCell};
use std::rc::Rc;
use std::pin::Pin;
use std::future::Future;
use futures::channel::oneshot::Canceled;
use futures::executor::block_on;
use futures::future::select_all;

fn run_queries_body() {
    let _futures: Vec<Pin<Box<dyn Future<Output=Result<(), Canceled>>>>> = Vec::new();
    let futuresRc = Rc::new(RefCell::new(_futures)); // TODO: Cell instead

    // This in actual could be called inside another future, so we need Rc<RefCell<...>>
    let mut futures = futuresRc.borrow_mut();
    let f3 = futures.iter().map(|x| *x);
    let (_res, _idx, remaining_futures) = block_on(select_all(f3));
    *futures = remaining_futures;
}
error[E0507]: cannot move out of `*x` which is behind a shared reference
  --> src/lib.rs:16:37
   |
16 |     let f3 = futures.iter().map(|x| *x);
   |                                     ^^ move occurs because `*x` has type `std::pin::Pin<std::boxed::Box<dyn futures::Future<Output = std::result::Result<(), futures::channel::oneshot::Canceled>>>>`, which does not implement the `Copy` trait

标签: vectorrustasync-awaitfuture

解决方案


问题不在于引脚 - 盒装的未来可以安全地与它的引脚一起移动,因为盒子意味着未来是堆分配的,所以移动盒子不会移动未来。该图钉用于禁止将未来移出其框框,但您不要尝试这样做。您的代码无法编译,因为Vec::iter()迭代了对元素的引用,并且您不能将对象移出引用,因为它会使原始值处于未定义状态。这种移动只允许用于可以简单复制的类型,例如数字或布尔值,这些类型由Copytrait 标记。编译器的消息令人困惑,因为它提到Pin<...>,但它这样做只是因为这是引用背后的文字类型,并且编译器报告所讨论的类型不是Copy,而没有暗示任何有关Pin语义的内容。

一个简单的解决方法是制作futures一个选项向量。这允许您通过调用Option::take. &mut Option<T>这是明确定义的,因为它提取值,但也留None在向量中的旧位置。

iter_mut()在您的情况下,您将使用(playground )迭代向量:

pub fn run_queries_body() {
    let futures: Vec<Option<Pin<Box<dyn Future<Output = Result<(), Canceled>>>>>> = vec![];
    let futures_rc = Rc::new(RefCell::new(futures));
    let mut futures = futures_rc.borrow_mut();
    let f3 = futures.iter_mut().map(|f| f.take().unwrap());
    let (_res, _idx, remaining_futures) = block_on(select_all(f3));
    *futures = remaining_futures.into_iter().map(Some).collect();
}

正如@Jmb 所指出的,一个更简单的方法是使用Vec::drain,它从向量中删除元素并为您提供删除元素的迭代器(playground):

pub fn run_queries_body() {
    let futures: Vec<Pin<Box<dyn Future<Output = Result<(), Canceled>>>>> = vec![];
    let futures_rc = Rc::new(RefCell::new(futures));
    let mut futures = futures_rc.borrow_mut();
    let f3 = futures.drain(..);
    let (_res, _idx, remaining_futures) = block_on(select_all(f3));
    *futures = remaining_futures;
}

推荐阅读