Rust Vectors

What is a Vector in Rust?

A vector is defined using the Vec<T> type, where T represents the type of elements stored. Vectors are stored in the heap, meaning their size can be adjusted dynamically during runtime.

Why Use Vectors?

  • Dynamic Sizing: Vectors can grow or shrink as needed.
  • Indexing: You can access elements using zero-based indexing.
  • Contiguous Memory: Elements are stored in a continuous block, making access and iteration fast.
  • Versatility: They can store any type that implements the Copy or Clone traits.

Creating a Vector

Vectors can be created in several ways:

1. Using Vec: :new

This method creates an empty vector. You can then add elements to it.

fn main() {
let mut numbers: Vec<i32> = Vec::new();
numbers.push(1);
numbers.push(2);
numbers.push(3);

println!("{:?}", numbers); // Output: [1, 2, 3]
}

2. Using the vec! Macro

The vec! macro initializes a vector with predefined values.

fn main() {
let numbers = vec![1, 2, 3];
println!("{:?}", numbers); // Output: [1, 2, 3]
}

Accessing Elements in a Vector

You can access elements in a vector using indexing or the .get() method.

1. Using Indexing

Indexing is straightforward but can cause a runtime panic if the index is out of bounds.

fn main() {
let numbers = vec![10, 20, 30];
println!("{}", numbers[1]); // Output: 20
}

2. Using .get()

The .get() method returns an Option<&T> to handle cases where the index might be invalid.

fn main() {
let numbers = vec![10, 20, 30];
match numbers.get(2) {
Some(value) => println!("Value: {}", value), // Output: Value: 30
None => println!("Index out of bounds!"),
}
}

Modifying a Vector

Vectors must be declared as mut to allow modification.

Adding Elements

  • Use .push() to add elements to the end.
  • Use .insert(index, value) to insert an element at a specific position.
fn main() {
let mut numbers = vec![1, 2, 3];
numbers.push(4); // Add to the end
numbers.insert(1, 5); // Insert 5 at index 1

println!("{:?}", numbers); // Output: [1, 5, 2, 3, 4]
}

Removing Elements

  • Use .pop() to remove the last element.
  • Use .remove(index) to remove an element at a specific index.
fn main() {
let mut numbers = vec![1, 2, 3, 4];
numbers.pop(); // Remove the last element
numbers.remove(1); // Remove the element at index 1

println!("{:?}", numbers); // Output: [1, 3]
}

Iterating Over a Vector

Rust provides multiple ways to iterate over a vector.

1. Using a for Loop

fn main() {
let numbers = vec![1, 2, 3];
for num in &numbers {
println!("{}", num); // Output: 1 2 3
}
}

2. Using an Iterator

fn main() {
let numbers = vec![1, 2, 3];
numbers.iter().for_each(|num| println!("{}", num)); // Output: 1 2 3
}

Common Operations on Vectors

Sorting

Sort a vector using .sort().

fn main() {
let mut numbers = vec![3, 1, 2];
numbers.sort();
println!("{:?}", numbers); // Output: [1, 2, 3]
}

Reversing

Reverse a vector using .reverse().

fn main() {
let mut numbers = vec![1, 2, 3];
numbers.reverse();
println!("{:?}", numbers); // Output: [3, 2, 1]
}

Checking for an Element

Use .contains() to check if a vector contains a specific value.

fn main() {
let numbers = vec![1, 2, 3];
println!("{}", numbers.contains(&2)); // Output: true
}

Safety and Ownership in Vectors

Rust enforces strict rules for ownership, borrowing and mutability in vectors:

  1. You cannot have simultaneous mutable and immutable references.
  2. Rust ensures memory safety when accessing or modifying vectors.

Example: Borrowing Rules

fn main() {
let mut numbers = vec![1, 2, 3];
let first = &numbers[0];
// numbers.push(4); // Error: Cannot modify while borrowing
println!("{}", first);
}

Performance Considerations

  • Vectors automatically allocate more memory as they grow, but this can be costly for large vectors.
  • Use .reserve() or .with_capacity() to pre-allocate memory when the size is known.
fn main() {
let mut numbers = Vec::with_capacity(10);
numbers.push(1);
println!("Capacity: {}", numbers.capacity()); // Output: Capacity: 10
}

Leave a Comment

BoxofLearn