I've been working my way through the book Rust in Action and i've seen The generic syntax Vec<T> where T is any type in my understanding but also i've seen Vec<_> which I read that infers the type based off of the contents of the vector. I was wondering what the distinction between Vec<T> and Vec<_> is because I can't tell the difference between them as they appear to do the same thing? Or their descriptions would seem to lead me to believe. Why would I use one vs the other?
- 614
- 1
- 6
- 20
-
https://stackoverflow.com/questions/34363984/what-is-vec – E_net4 Dec 13 '21 at 16:52
2 Answers
The _ is called a wildcard. It basically tells Rust to just deduce the type needed, and that's it.
For Vec<T> it's a generic it does two things, it names the type, but also is a generic parameter for any type. Since you don't know what type it can be, you use T to tell in places where it should be that type, where to get the information from (in a sense).
So _ means any type, but deduced in context (a unique type), T is a generic type, and can be many types (a new generation is done for each separate type it encounters).
- 2,411
- 1
- 19
- 24
Vec<T> could be defined as (the actual definition is more complex):
pub struct Vec<T> {
buf: RawVec<T>,
len: usize,
}
As such, it's called Vec<T> because that's how the generic struct is defined.
When creating a Vec, you have to specify what the type of the elements are:
let x: Vec<u8> = vec![1, 2, 3];
Here, the type annotation isn't actually needed, since the compiler can infer it for us.
Let's say we want to obtain all of the command line arguments as a Vec. We could try:
let args = std::env::args().collect();
...but that fails with:
error[E0282]: type annotations needed
--> src/main.rs:2:9
|
2 | let args = std::env::args().collect();
| ^^^^ consider giving `args` a type
since we didn't specify which container to collect the arguments into: .collect() can collect the iterator elements into a Vec<T>, a Box<[T]>, a LinkedList<T>, and many more. Let's specify a type:
let args: Vec<String> = std::env::args().collect();
This compiles, but we can make this a bit simpler: we can do
let args: Vec<_> = std::env::args().collect();
and get the same effect, since the _ tells the compiler to infer what the type is. Since there is only one possible type inferred by the compiler, it replaces the _ with String. Vec<_> isn't a type, it's a partial type that makes the compiler fill in the _.
- 4,770
- 2
- 20
- 53