vector - 试图在Rc <RefCell <... >>内部修改 future Vec

标签 vector rust async-await future

我尝试等待并从 future 的Vec中删除一对一的 future 。这没用。我了解为什么它不起作用: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

最佳答案

问题不在钉子上-装箱的 future 可以安全地与钉子一起移动,因为箱子意味着将来是堆分配的,因此移动箱子不会移动 future 。该固定销用于禁止将 future 从其包装箱中移出,但您不要尝试这样做。您的代码无法编译,因为Vec::iter()会在对元素的引用上进行迭代,并且您无法将对象移出引用,因为它将使原始值保持未定义状态。这种移动仅适用于可以被简单复制的类型,例如数字或 bool 值,这些类型由Copy特性标记。编译器的消息令人困惑,因为它提到了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;
}

关于vector - 试图在Rc <RefCell <... >>内部修改 future Vec,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63801495/

相关文章:

c# - MoveNext 而不是实际的方法/任务名称

matlab - 在matlab中定义向量的动态增量步骤

c++ - 用零填充 vector

rust - 从泛型函数内部调用的特征

rust - 我如何返回对拥有的和活着的东西的引用?

javascript - 未捕获( promise )TypeError : Cannot read property 'forEach' of undefined

ASP.NET MVC 4 异步数据库调用 : never returns the HTTP response

android - EditText drwableLeft 不适用于向量

c++ - int vector 中的字符串 vector ?

json - 反序列化为具有枚举成员的结构