Skip to content

12 · Vec and Collections

Vec<T> is the standard growable array. Creating or pushing into a Vec requires the !alloc effect — the compiler makes heap allocation explicit in the type. Iteration is zero-cost: for loops and iterator adapters like map, filter, and fold compile to the same code as a hand-written loop.

collections.cssl
fn main() !io !alloc {
// Build a Vec by pushing.
let mut nums: Vec<i32> = Vec::new();
for i in 0..5 {
nums.push(i * i); // 0, 1, 4, 9, 16
}
// Iterate by reference.
println!("squares:");
for n in &nums {
println!(" {}", n);
}
// Functional-style — produces a new Vec.
let evens: Vec<i32> = nums.iter()
.filter(|&&x| x % 2 == 0)
.copied()
.collect() !alloc;
println!("even squares: {:?}", evens);
// Fold to sum.
let total: i32 = nums.iter().fold(0, |acc, &x| acc + x);
println!("sum = {}", total);
// Vec::from for a known-size literal.
let words: Vec<str> = Vec::from(["alpha", "beta", "gamma"]) !alloc;
println!("words: {:?}", words);
}
squares:
0
1
4
9
16
even squares: [0, 4, 16]
sum = 30
words: ["alpha", "beta", "gamma"]

Every !alloc site in the function body is visible in the function signature. This makes memory allocation auditable by reading type signatures alone — no hidden allocations from library calls. The iterator chain (filter → copied → collect) is fused by the compiler into a single pass with no intermediate allocations. Out-of-bounds indexing via nums[i] carries !panic; use nums.get(i) for a bounds-checked Option<&i32> with no effect.


Next → 13 · Error Handling