我正在编写一个使用Rust从oxfordlearnersdictionaries.com抓取链接的程序。我正在使用hyper
和futures
。
我有一系列指向每个部分的链接,并使用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>>>
。如何将其合并到Stream
个Vec
,例如使用stream::futures_unordered
合并Future
?
修改:我尝试合并stream::iter_ok
和stream::Stream::flatten
:
let flattened = ::futures::stream::iter_ok(jobs)
.flatten();
但由于我想异步发送多个Web请求,因此效率不高。只要内部Stream
准备就绪,合并后的Stream
就会产生价值。
答案 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
组合子,但还没有一个用于流的组合。也许您可以自己实现它并将其作为拉取请求提交!