How to tell the compiler the type of an empty Vec
Short answer: an empty Vec has no elements to infer a type from, so the element type has to be
written down: either annotate the binding (let v: Vec<i32> = Vec::new();) or use the turbofish
(let v = Vec::<i32>::new();). The annotation usually reads better; the turbofish earns its place
when the type has to sit inside an expression.
Each block below is a complete src/main.rs; the blocks that print run with cargo run, the failing
one with cargo build. Rust 1.99.0, edition 2024. The project name doesn’t matter — nothing printed
here depends on it.
The error you came for
Section titled “The error you came for”Write an empty Vec and use it before anything has constrained its element type:
fn main() { let numbers = Vec::new(); println!("{numbers:?}");}error[E0282]: type annotations needed for `Vec<_>` --> src/main.rs:2:9 |2 | let numbers = Vec::new(); | ^^^^^^^ ---------- type must be known at this point |help: consider giving `numbers` an explicit type, where the type for type parameter `T` is specified |2 | let numbers: Vec<T> = Vec::new(); | ++++++++
For more information about this error, try `rustc --explain E0282`.Vec::new() is generic over the element type — its real signature is fn new() -> Vec<T> — and an
empty Vec never says what T is. The _ in Vec<_> is the compiler pointing at the one thing it
couldn’t work out. The help line is fix two below, with T standing in for the element type you
actually want.
Fix one: the turbofish
Section titled “Fix one: the turbofish”::<i32> feeds the type argument straight to the call, and the name comes from the shape:
fn main() { let mut numbers = Vec::<i32>::new(); numbers.push(1); numbers.push(2); println!("{numbers:?}");}[1, 2]Fix two: the annotation
Section titled “Fix two: the annotation”The same type, written where Rust already puts types for every other binding:
fn main() { let mut numbers: Vec<i32> = Vec::new(); numbers.push(1); numbers.push(2); println!("{numbers:?}");}[1, 2]Both fixes are exactly equivalent, so the choice is about reading. The annotation wins more often
than not: the element type sits at the left edge where you look for it, it reads like
let count: i32 = 0, and it stays readable when the type gets long — Vec<(String, usize)> in a
turbofish is a mouthful. Reach for the turbofish when there’s no binding to annotate; the case you’ll
meet most often is collect():
fn main() { let doubled = (1..=3).map(|n| n * 2).collect::<Vec<i32>>(); println!("{doubled:?}");}[2, 4, 6]Iterators are a chapter of their own; the point here is only that ::<> is the same operator you
already used on Vec::new().
When you don’t write anything at all
Section titled “When you don’t write anything at all”The error only fires when nothing constrains the type. One push is a constraint, so this compiles
with no annotation anywhere:
fn main() { let mut numbers = Vec::new(); numbers.push(1); println!("{numbers:?}");}[1]That’s why the same Vec::new() line that failed at the top of this page works here: the type was
inferred from the first element, not written down. The catch is that the first push fixes the type
for the whole binding — push a String and every later element must be a String too.
Related
Section titled “Related”- What is the difference between an array and a Vec? — the other growable-versus-fixed trade-off
- What is the difference between a Vec and a slice? — who owns the buffer
- Which collection should you use? —
where
Vecfits among the rest
Next in this chapter: how to store different types in one Vec.