如何Iterator ::链接迭代器的向量?

时间:2015-09-26 13:36:26

标签: rust

对于给定的迭代器集合a,b,c,可以使用a.chain(b).chain(c)成功链接它们。由于我尝试编写的CLI util提供了一个路径向量(字符串, - dirs“a / b / c”“d / e / f”......),我想使用walkd_dir他们每个人然后将他们连在一起。我的第一个想法是:

fn main() {
    let a = 0..3;
    let b = 3..6;
    let c = 6..9;
    let v = vec![b, c];
    v.iter().cloned().fold(a, |acc, e| acc.chain(e));
}

http://is.gd/hfNQd2,返回

<anon>:6:40: 6:52 error: mismatched types:
 expected `core::ops::Range<_>`,
    found `core::iter::Chain<core::ops::Range<_>, core::ops::Range<_>>`
(expected struct `core::ops::Range`,
    found struct `core::iter::Chain`) [E0308]
<anon>:6     v.iter().cloned().fold(a, |acc, e| acc.chain(e));

另一次尝试http://is.gd/ZKdxZM,虽然a.chain(b).chain(c)有效。

2 个答案:

答案 0 :(得分:8)

使用flat_map

fn main() {
    let a = 0..3;
    let b = 3..6;
    let c = 6..9;
    let v = vec![a, b, c];
    v.iter().flat_map(|it| it.clone());
}

答案 1 :(得分:1)

正如错误消息所述,Range的类型与Chain<Range, Range>的类型不同,并且调用fold中累加器的类型必须始终保持一致。否则,如果向量中没有项目,返回类型将来自fold

最简单的解决方案是使用特征对象,特别是Box<Iterator>

type MyIter = Box<Iterator<Item=i32>>;

fn main() {
    let a = 0..3;
    let b = 3..6;
    let c = 6..9;
    let v = vec![b, c];
    let z = v.into_iter().fold(Box::new(a) as MyIter, |acc, e| {
        Box::new(acc.chain(Box::new(e) as MyIter)) as MyIter
    });

    for i in z {
        println!("{}", i);
    }
}

这增加了一个间接级别,但将两种具体类型(RangeChain)统一为一种类型。

一个可能更有效但更长的类型版本是创建代表enumRange的{​​{1}},然后实现{{1对于那种新类型。

实际上,我不认为Chain会起作用,因为它需要递归定义,这是不允许的。