Rust Vectors

Dynamic, growable arrays in Rust

📈 What are Rust Vectors?

Vectors are dynamic, growable arrays that can change size at runtime. Unlike arrays, vectors are heap-allocated and can store varying amounts of data, making them perfect for collections where the size isn't known at compile time.


fn main() {
    // Create a new empty vector
    let mut numbers = Vec::new();
    
    // Add elements
    numbers.push(1);
    numbers.push(2);
    numbers.push(3);
    
    println!("Vector: {:?}", numbers);
    println!("Length: {}", numbers.len());
}
                                    

Output:

Vector: [1, 2, 3]

Length: 3

Vector Features

Vector Characteristics

📏

Dynamic Size

Can grow and shrink at runtime

vec.push(item); vec.pop();
🏠

Heap Allocated

Stored on the heap for flexibility

let vec = Vec::new();
🎯

Same Type

All elements must be the same type

let nums: Vec = vec![];
🔢

Index Access

Access elements by index like arrays

let first = vec[0];

🔹 Creating Vectors

Different ways to create vectors in Rust:

fn main() {
    // Empty vector with explicit type
    let mut numbers: Vec = Vec::new();
    
    // Using vec! macro with initial values
    let fruits = vec!["apple", "banana", "cherry"];
    
    // Vector with repeated values
    let zeros = vec![0; 5];  // [0, 0, 0, 0, 0]
    
    // Vector with capacity pre-allocated
    let mut with_capacity = Vec::with_capacity(10);
    
    // Add some elements to demonstrate
    numbers.push(1);
    numbers.push(2);
    numbers.push(3);
    
    println!("Numbers: {:?}", numbers);
    println!("Fruits: {:?}", fruits);
    println!("Zeros: {:?}", zeros);
    println!("Capacity: {}", with_capacity.capacity());
}

Output:

Numbers: [1, 2, 3]

Fruits: ["apple", "banana", "cherry"]

Zeros: [0, 0, 0, 0, 0]

Capacity: 10

🔹 Adding and Removing Elements

Vectors can grow and shrink dynamically:

fn main() {
    let mut scores = vec![85, 90, 78];
    
    // Add elements to the end
    scores.push(92);
    scores.push(88);
    println!("After push: {:?}", scores);
    
    // Remove and return the last element
    let last = scores.pop();
    println!("Popped: {:?}", last);
    println!("After pop: {:?}", scores);
    
    // Insert at specific position
    scores.insert(1, 95);  // Insert 95 at index 1
    println!("After insert: {:?}", scores);
    
    // Remove at specific position
    let removed = scores.remove(2);  // Remove element at index 2
    println!("Removed: {}", removed);
    println!("Final: {:?}", scores);
}

Output:

After push: [85, 90, 78, 92, 88]

Popped: Some(88)

After pop: [85, 90, 78, 92]

After insert: [85, 95, 90, 78, 92]

Removed: 90

Final: [85, 95, 78, 92]

🔹 Accessing Vector Elements

Safe and unsafe ways to access vector elements:

fn main() {
    let colors = vec!["red", "green", "blue", "yellow"];
    
    // Direct indexing (can panic if index is invalid)
    println!("First color: {}", colors[0]);
    
    // Safe access with get() method
    match colors.get(2) {
        Some(color) => println!("Third color: {}", color),
        None => println!("No color at index 2"),
    }
    
    // Safe access for potentially invalid index
    match colors.get(10) {
        Some(color) => println!("Color at index 10: {}", color),
        None => println!("No color at index 10"),
    }
    
    // Get first and last elements safely
    println!("First: {:?}", colors.first());
    println!("Last: {:?}", colors.last());
    
    // Vector length
    println!("Number of colors: {}", colors.len());
}

Output:

First color: red

Third color: blue

No color at index 10

First: Some("red")

Last: Some("yellow")

Number of colors: 4

🔹 Iterating Over Vectors

Different ways to iterate through vector elements:

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];
    
    // Method 1: Immutable iteration
    println!("Method 1 - Immutable iteration:");
    for num in &numbers {
        println!("  {}", num);
    }
    
    // Method 2: Mutable iteration
    println!("\nMethod 2 - Mutable iteration (doubling values):");
    for num in &mut numbers {
        *num *= 2;
    }
    println!("  Doubled: {:?}", numbers);
    
    // Method 3: Taking ownership
    println!("\nMethod 3 - Taking ownership:");
    for num in numbers {
        println!("  Owned: {}", num);
    }
    // numbers is no longer accessible here
    
    // Method 4: With index using enumerate
    let fruits = vec!["apple", "banana", "cherry"];
    println!("\nMethod 4 - With index:");
    for (index, fruit) in fruits.iter().enumerate() {
        println!("  {}: {}", index, fruit);
    }
}

Output:

Method 1 - Immutable iteration:

1

2

3

4

5


Method 2 - Mutable iteration (doubling values):

Doubled: [2, 4, 6, 8, 10]

🔹 Vector Methods and Operations

Useful methods for working with vectors:

fn main() {
    let mut data = vec![3, 1, 4, 1, 5, 9, 2, 6];
    
    // Length and capacity
    println!("Length: {}, Capacity: {}", data.len(), data.capacity());
    
    // Check if empty
    println!("Is empty: {}", data.is_empty());
    
    // Contains element
    println!("Contains 5: {}", data.contains(&5));
    
    // Clear all elements
    let mut temp = data.clone();
    temp.clear();
    println!("After clear - Length: {}", temp.len());
    
    // Extend with another vector
    let more_data = vec![8, 7];
    data.extend(more_data);
    println!("After extend: {:?}", data);
    
    // Retain elements that match condition
    data.retain(|&x| x > 3);
    println!("After retain (>3): {:?}", data);
    
    // Sort the vector
    data.sort();
    println!("After sort: {:?}", data);
}

Output:

Length: 8, Capacity: 8

Is empty: false

Contains 5: true

After clear - Length: 0

After extend: [3, 1, 4, 1, 5, 9, 2, 6, 8, 7]

After retain (>3): [4, 5, 9, 6, 8, 7]

After sort: [4, 5, 6, 7, 8, 9]

🧠 Test Your Knowledge

What is the main difference between arrays and vectors in Rust?