Why can't the compiler the type of an iterator `collect()` call?


#1

For example:

let v = b"3q2+7w==".iter().cloned().collect();

The compiler complains with:

133 |         let v = b"3q2+7w==".iter().cloned().collect();
    |             ^
    |             |
    |             consider giving `v` a type
    |             cannot infer type for `_`

If I change to:

let v: Vec<u8> = b"3q2+7w==".iter().cloned().collect();

The program compiles without problems. If cloned() returns an object that implements Iterator<Item=u8> then collect() should return a Vec<u8>, yet the compiler seems to require type information. Am I missing something obvious?

Thanks in advance.


#2

collect() can return other things.

use ::std::collections::HashSet;

let v: HashSet<u8> = b"3q2+7w==".iter().cloned().collect();

#3

You can collect into any type that implements FromIterator so it’s ambiguous if type inference can’t deduce it. Vec is just one type that implements FromIterator but there can be arbitrary other options.


#4

Makes sense, thanks.


#5

I think I remember some chatter about using defaulted type parameters to inform type inference, so something like:

fn collect<B = Vec<Self::Item>>(self) -> B
    where B: FromIterator<Self::Item>

so that it would collect to Vec by default if otherwise ambiguous. Somebody would need to write an RFC.


#6

I don’t think there is a sensible default for collect. I much prefer having the caller provide the type explicitly or through inference.