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.
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());
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With