如何合并流的迭代器?

时间:2018-02-14 11:17:44

标签: rust

我正在编写一个使用Rust从oxfordlearnersdictionaries.com抓取链接的程序。我正在使用hyperfutures

我有一系列指向每个部分的链接,并使用stream::unfold构建对每个部分的访问权限:

// Returns the links scraped, and probably Uri to the next page.
fn process_body_and_return_next(body: Body) -> (Vec<String>, Option<Uri>) { ... }

// In main()
let mut core = Core::new().unwrap();
let handle = core.handle();
let client = Client::new(&handle);
let uris = ...

let jobs = uris.map(|uri| {
    stream::unfold(Some(uri), |uri| {
        uri.map(|uri| {
            client
                .get(uri)
                .and_then(|res| res.body().concat2())
                .map(process_body_and_return_next)
        })
    })
});

现在我有一个impl Iterator<Item = impl Stream<Item = Vec<String>>>。如何将其合并到StreamVec,例如使用stream::futures_unordered合并Future

修改:我尝试合并stream::iter_okstream::Stream::flatten

let flattened = ::futures::stream::iter_ok(jobs)
    .flatten();

但由于我想异步发送多个Web请求,因此效率不高。只要内部Stream准备就绪,合并后的Stream就会产生价值。

2 个答案:

答案 0 :(得分:2)

可以使用futures::stream::iter_ok将迭代器转换为流,这样可以将流的迭代器转换为流的流:

::futures::stream::iter_ok(jobs)

然后,您可以使用Stream::flatten()将此流媒体流展平为所有项目的单个流:

let flattened = ::futures::stream::iter_ok(jobs)
    .flatten();

答案 1 :(得分:0)

select组合子需要两个Stream s并在两个流中的一个准备就绪时产生。

为了从两个以上的流中进行选择,您可以将呼叫链接到select。但是,由于您事先并未知道必须选择的流的数量,因此您必须将中间流包装起来以删除特定的Stream类型,以便程序类型的检查。

extern crate futures;

use futures::Stream;

fn select_all<'a, I, T, E>(seq: I) -> Box<Stream<Item = T, Error = E> + 'a>
where
    I: IntoIterator,
    I::Item: Stream<Item = T, Error = E> + 'a,
    T: 'a,
    E: 'a,
{
    let mut iter = seq.into_iter();
    let mut result = Box::new(iter.next().expect("got an empty list of streams"))
        as Box<Stream<Item = T, Error = E>>;
    while let Some(next) = iter.next() {
        result = Box::new(result.select(next));
    }

    result
}

然而,实现这一点肯定是一种更有效的方法。期货有一个select_all组合子,但还没有一个用于流的组合。也许您可以自己实现它并将其作为拉取请求提交!