Type Annotations for Vector

Hi,
Just a quick question on the code below. It seems reasonable to me that if Rust can infer the type of v, it should be able to infer the type of w. Is there some technical reason why the compiler needs a type annotation for w?
Thanks!

let v = vec![1,2,3]; //ok

let w = v.iter().map(|x| x + 1).collect(); //error[E0282]: type annotations needed

println!("{:?}", w);   //2, 3, 4

Hi, you can collect in other types than Vec.
For example:

use std::collections::HashSet;

fn main() {
    let v = vec![1,2,3];

    let w: HashSet<_> = v.iter().map(|x| x + 1).collect();
    
    println!("{:?}", w);
}

But it can be anything implementing the FromIterator trait, so you can make it work with a type in your code base too.

Hi leudz,
Thanks for your reply. I don't think it answers my question though.

Even if we looked at your HashSet example, what is the point of the code below? If Rust is inferring the type due to the generic code below, why do we need it at all?

HashSet<_> // why do we need this? If Rust does not need us to explicitly use HashSet<I32>, why is HashSet<_> acceptable with no concrete type?

This also works for my vector example but again, why the need for "Vec<_>" at all?

let w: Vec<_> = v.iter().map(|x| x + 1).collect();

Because the compiler can't know the type you want, Vec<T>, HashSet<T>, an other type?
It can guess the type T that's why you can use _ but that's it.

If we look at Iterator::collect's definition:

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

we can see two generic types, B and Self::Item.

The compiler knows Self::Item because it is specified by self, the type you are iterating on. In your example the iterator is Map<Iter<'_, i32>> and its Self::Item is i32.

But the compiler needs more information to determine B. You can directly tell it the type or do something like a function call, method,... that will guide the compiler.

You don't have to tell it again what Self::Item is though, hence the underscore.

1 Like

Thanks leudz.
I think I get it now.....I was confusing two different types:

a) The type of container i.e. Vec or HashSet. Rust cannot guess what container I want to collect into which seems completely fair, so I need to specify Vec or HashSet etc.
b) The type that the container contains i.e. T. As you pointed out, Rust can guess what T is, but you just need to let it know what container you want.

Thanks for your help!