如何将Futures 0.1迭代器收集到向量中?

时间:2019-12-05 11:00:03

标签: rust future

我正在尝试使用Rust 1.36.0和Futures 0.1建立期货向量。

  1. 为什么下面的代码不起作用?
  2. 是否有更惯用的方式来构建{/ {1}}的列表/可重复项?
Future

我的extern crate futures; pub fn create_some_futures() { let mapped: Vec<Box<dyn futures::future::Future<Item = i32, Error = ()>>> = (0..10) .map(|_| Box::new(futures::future::ok(132))) .collect(); } fn main() { create_some_futures(); }

Cargo.toml

无法编译:

[dependencies]
futures = "0.1"

那是为什么?我怀疑将error[E0277]: a collection of type `std::vec::Vec<std::boxed::Box<dyn futures::Future<Item = i32, Error = ()>>>` cannot be built from an iterator over elements of type `std::boxed::Box<futures::Failed<{integer}, _>>` --> src/main.rs:6:10 | 6 | .collect(); | ^^^^^^^ a collection of type `std::vec::Vec<std::boxed::Box<dyn futures::Future<Item = i32, Error = ()>>>` cannot be built from `std::iter::Iterator<Item=std::boxed::Box<futures::Failed<{integer}, _>>>` | = help: the trait `std::iter::FromIterator<std::boxed::Box<futures::Failed<{integer}, _>>>` is not implemented for `std::vec::Vec<std::boxed::Box<dyn futures::Future<Item = i32, Error = ()>>>` 转换为futures::Finished<{integer}, _>会出现问题,因为这样可以很好地编译:

<dyn futures::Future<Item = i32, Error = ()>>

我不确定是什么问题。函数pub fn create_some_boxed_ints() { let mapped: Vec<Box<i32>> = (0..10).map(|_| Box::new(132)).collect(); } 返回实现future::ok的{​​{1}},我希望它与FutureResult兼容。

我正在使用旧版本的期货箱,因为我要参与的另一个项目正在使用0.1版本。我知道Future的关联类型在0.3.x中是dyn Future<Item = i32, Error = ()>。如果切换到最新版本,也许不会有这个问题,但是我想了解一下上面的情况,以便更好地了解Rust。错误消息与1.39.0相同。

1 个答案:

答案 0 :(得分:1)

为什么下面的代码不起作用?

我认为此问题并非特定于您使用的期货版本-如果我更新您的代码以使用Future<Output = Result<i32, i32>>,那么我得到exactly the same result

这里的问题是,您的映射功能需要将具体的未来胁迫为特征对象。

在Rust参考中,type coercions的小节中将强制位置描述为:

  

需要的类型是显式的或可以通过从显式类型的传播而派生的地方(无类型推断)。

您的代码需要强制转换的上下文将需要类型推断-从所需的容器类型到map函数的返回类型进行反向操作。这是一座太遥远的桥梁。

您可以通过显式转换为特征对象来克服它:

Box::new(futures::future::ok(132)) as Box<dyn futures::future::Future<Output = Result<i32, i32>>>

现在它将编译(playground)

为避免隐式转换,您可以在map闭包中添加返回类型:

let mapped: Vec<Box<dyn futures::future::Future<Output = Result<i32, i32>>>> = (0..10)
    .map(|_| -> Box<dyn futures::future::Future<Output = Result<i32, i32>>> {
        Box::new(futures::future::ok(132))
    })
    .collect();

这将使隐性强制生效。

是否有一种更惯用的方式来构建{/ {1}}的列表/可重复项?

这将取决于期货的创建方式和用途。

  • 您可以定义类型别名:

    Future

    这样您就可以写:

    type MyDynFuture = Box<dyn futures::future::Future<Output = Result<i32, i32>>>;
    

    我个人认为它更具可读性。

  • 如果您的代码库中有很多地方需要 管理期货的集合,您可能想使用一个函数 而不是关闭以进一步减少样板。

  • 如果该集合将包含有限的将来类型集合,则可能是 定义包含它们并收集的枚举更有效 枚举在容器中的实例-这样可以避免运行时 分派和堆分配。

  • 如果从某个迭代器生成期货,则 集合将传递给join_all或其他类似的对象 方法,这样您就可以等待它们全部完成,然后就不需要了 完全收集它们-例如:

    let mapped: Vec<MyDynFuture> = (0..10)
        .map(|_| -> MyDynFuture {
            Box::new(futures::future::ok(132))
        })
        .collect();
    

注意:我也对Rust缺乏经验,可能还有其他我不知道的最佳实践。