vec! Macro
The vec! macro in the standard library prelude constructs a Vec<T> inline using either a comma-separated list of elements (vec![a, b, c]) or a repeat-value expression (vec![value; count]).
The Two Syntactic Forms of vec!
| Macro Form | Syntax | What It Does | Trait Bounds on T |
|---|---|---|---|
| List form | vec![e1, e2, e3] |
Allocates a Vec<T> of capacity 3 and moves e1, e2, e3 into it |
None (T: Sized) |
| Repeat form | vec![elem; n] |
Evaluates elem once, allocates capacity n, clones elem n - 1 times, and moves elem into the last slot |
T: Clone |
| Empty form | vec![] |
Expands to Vec::new() (zero heap allocation) |
None (T: Sized) |
(Note: Just like function arguments and array literals, vec![e1, e2,] permits a trailing comma.)
How the List Form Avoids Reallocations
Rather than creating an empty Vec::new() and calling .push() repeatedly (which would trigger multiple reallocations), vec![a, b, c] places the elements into a boxed fixed-size array Box<[T; N]> and converts that single heap allocation directly into a Vec<T> with len == N and capacity == N:
fn main() {
let items = vec!["rust", "cargo", "clippy"];
println!(
"items = {items:?} (len = {}, capacity = {})",
items.len(),
items.capacity()
);
}
items = ["rust", "cargo", "clippy"] (len = 3, capacity = 3)
Repeat Form (vec![elem; n]) and Specialization for Zeroed Primitives
In vec![elem; n], n can be any runtime usize expression (unlike [elem; N] array repeat syntax, where N must be a compile-time const):
fn make_grid_row(width: usize, default_val: i32) -> Vec<i32> {
vec![default_val; width]
}
fn main() {
let row = make_grid_row(5, -1);
let flags = vec![String::from("ready"); 3];
println!("Row: {row:?}");
println!("Flags: {flags:?}");
}
Row: [-1, -1, -1, -1, -1]
Flags: ["ready", "ready", "ready"]
OS Zero-Page Optimization for vec![0; n]
When you write vec![0_u8; n], vec![0_i32; n], or any repeat expression where the element is all-zero bits, the standard library specializes vec! to call the allocator's alloc_zeroed (calloc) path instead of allocating uninitialized memory and writing zeros in a loop. For large buffers, the operating system can back vec![0_u8; n] with virtual zero pages lazily without touching every physical page upfront.
Initializing Independent Non-Clone Elements (std::iter::repeat_with)
If T does not implement Clone, or if each slot needs a freshly constructed independent value (such as unique IDs or separate channels), use std::iter::repeat_with(|| ...).take(n).collect() or (0..n).map(|i| ...).collect() instead of vec![elem; n].