I am trying to collect a iterator of iterators into a vector of iterators. As the name of the composite type is quite long, I tried to simplify it using generics:
// impl<I: Iterator>
let iters = filenames.iter().map(|filename| {
let fpath = format!("{}//{}", dirname, filename);
let file = File::open(&fpath).expect("Fail to open file");
let reader = BufReader::new(file);
reader.lines().peekable()
}).collect::<Vec<Peekable<I>>>();
However, I ended up with an error:
a collection of type `std::vec::Vec<std::iter::Peekable<I>>`
cannot be built from an iterator over elements of type
`std::iter::Peekable<std::iter::Skip<std::io::Lines<std::io::BufReader<std::fs::File>>>>`
That is quite strange in my sense. Considering that std::io::Lines has implemented Iterator, why can't the collection be built?
Your code tries to collect to Peekable<I> but you have Peekable<Skip<Lines<...>>> instead, so the compiler rejects the obvious type mismatch. It's unclear how your I type is related to this code, but your final value definitely doesn't have any I in it, it's a concrete type (as printed out by the compiler).
In this case, writing collect::<Vec<_>> will probably be enough.
It's in fact a typo (I simplified the snippet while forgot to update the output)
The original snippet looks like that:
// impl<I: Iterator>
let iters = filenames.iter().map(|filename| {
let fpath = format!("{}//{}", dirname, filename);
let file = File::open(&fpath).expect("Fail to open file");
let reader = BufReader::new(file);
reader.lines().skip(1).peekable()
}).collect::<Vec<Peekable<I>>>();
And you are right, Vec<_> works like a charm.
But still, I am puzzled by the behaviour of the compiler -- why does the compiler fail to derive the type even if I have provided a more detailed annotation?
Or more precisely, what the generic annotation should be so that it could match std::io::Lines? Like Iterator + Debug?