DEV Community

Cover image for πŸš€ Mastering Vectors in Rust
Ann Maina
Ann Maina

Posted on

πŸš€ Mastering Vectors in Rust

In Session 6 of the Polkadot Kisumu Bootcamp, we dived deep into one of the most practical and powerful data structures in Rust: Vectors.

If you’ve ever needed to store a list of items that can change size, vectors are your best friend in Rust.

What Is a Vector?

A vector is a resizable array that stores values on the heap. It's useful when you don’t know the size of your data at compile time.

fn main() {
    let mut numbers = Vec::new();
    numbers.push(10);
    numbers.push(20);
    println!("{:?}", numbers); // Output: [10, 20]
}

Enter fullscreen mode Exit fullscreen mode

πŸ”„ Using .push() and .pop()

These are the basic ways to grow or shrink a vector.

fn main() {
    let mut fruits = vec!["apple", "banana"];
    fruits.push("mango");  // Add item
    fruits.pop();          // Remove last item
    println!("{:?}", fruits); // Output: ["apple", "banana"]
}

Enter fullscreen mode Exit fullscreen mode

βœ‚οΈ Slices – Borrowing Part of a Vector

Slices let you access a section of the vector without taking ownership.

fn main() {
    let data = vec![1, 2, 3, 4, 5];
    let slice = &data[1..4];
    println!("{:?}", slice); // Output: [2, 3, 4]
}
Enter fullscreen mode Exit fullscreen mode

This is memory-efficient and avoids unnecessary copying.

🧬 Generics – Writing Flexible Code

Generics in Rust let you write functions or types that work with any data type, as long as the type meets certain conditions.

Instead of writing duplicate code for each type (i32, String, etc.), you can use a generic type parameter like T.

fn print_all<T: std::fmt::Debug>(items: Vec<T>) {
    for item in items {
        println!("{:?}", item);
    }
}

Enter fullscreen mode Exit fullscreen mode

What's Happening:

T is a placeholder for any type.

T: std::fmt::Debug means the type T must implement the Debug trait so it can be printed.

You can now call print_all() with Vec, Vec<&str>, Vec, etc.

fn main() {
    let numbers = vec![1, 2, 3];
    let names = vec!["Ann", "Ben", "Chris"];

    print_all(numbers);
    print_all(names);
}
Enter fullscreen mode Exit fullscreen mode

🧠 Generics = less repetition + more flexibility.
This is the Rust way to write clean, DRY (Don't Repeat Yourself), scalable code.

πŸ” Iteration Methods – Understanding Ownership in Loops

.iter() – Immutable Borrow

You borrow each item without modifying or taking ownership.

let nums = vec![1, 2, 3];
for n in nums.iter() {
    println!("{}", n); // Can read, but not modify
}
// nums is still usable here

Enter fullscreen mode Exit fullscreen mode

Use this when you just want to read from the vector.

.iter_mut() – Mutable Borrow

You borrow each item mutably, which means you can change the values.

let mut nums = vec![1, 2, 3];
for n in nums.iter_mut() {
    *n *= 2; // Modify in-place
}
println!("{:?}", nums); // Output: [2, 4, 6]
Enter fullscreen mode Exit fullscreen mode

Use this when you need to edit values in the vector.

.into_iter() – Take Ownership

You move each item out of the vector β€” meaning the original vector is no longer usable after the loop.

let nums = vec![1, 2, 3];
for n in nums.into_iter() {
    println!("{}", n);
}
// nums is now invalid β€” ownership moved

Enter fullscreen mode Exit fullscreen mode

βœ… Use this when you're done with the vector and want to consume it completely.

Why This Matters

Understanding generics and iteration methods gives you real power in Rust:

  • You write once, reuse everywhere (generics).
  • You control how memory is accessed, modified, or moved (iterators).
  • It ties directly back to ownership and borrowing, which are core to writing safe, high-performance Rust.

This builds on earlier sessions like ownership and borrowing making your code more safe, clean, and production-ready.

Top comments (0)