12

for a given set of iterators a, b, c, one can chain them successfully with a.chain(b).chain(c). Since the CLI util I am trying to write provides a vector of paths (strings, --dirs "a/b/c" "d/e/f" ...), I would like to use walkd_dir on each of them and then chain them together. My first thought is:

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, returns

<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));

Another attempt http://is.gd/ZKdxZM, although a.chain(b).chain(c) works.

2 Answers 2

17

Use 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());
}
Sign up to request clarification or add additional context in comments.

1 Comment

We can do without the clone() by using into_iter() like this: `v.into_iter().flat_map(|it| it);
2

As the error message states, the type of a Range is different than the type of Chain<Range, Range>, and the type of the accumulator in the call the fold must always be consistent. Otherwise, what would the return type be from the fold if there were no items in the vector?

The simplest solution is to use a trait object, specifically 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);
    }
}

This adds a level of indirection but unifies the two concrete types (Range, Chain) as a single type.

A potentially more efficient but longer-to-type version would be to create an enum that represented either a Range or a Chain, and then implement Iterator for that new type.

Actually, I don't think the enum would work as it would require a recursive definition, which is not allowed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.