google-site-verification: google61fe8ba583a51912.html
Complete Guide to Rust Vectors

Introduction to Vectors in Rust

Vectors (Vec<T>) are one of the most commonly used collections in Rust. They provide a dynamic, growable array that stores elements of the same type in contiguous memory. Vectors are heap-allocated and offer flexible sizing while maintaining fast access times.

Key Concepts

  • Dynamic Sizing: Grows and shrinks at runtime
  • Type Safety: All elements must be the same type
  • Memory Contiguous: Elements stored sequentially in memory
  • Ownership: Vector owns its elements
  • Performance: O(1) index access, amortized O(1) push

1. Creating Vectors

Basic Creation Methods

fn main() { // Method 1: Vec::new() - empty vector let mut v1: Vec<i32> = Vec::new(); v1.push(1); v1.push(2); println!("v1: {:?}", v1); // Method 2: vec! macro - with initial values let v2 = vec![1, 2, 3, 4, 5]; println!("v2: {:?}", v2); // Method 3: vec! macro with repeated value let v3 = vec![0; 10]; // Creates vector with 10 zeros println!("v3: {:?}", v3); // Method 4: From iterator let v4: Vec<i32> = (0..5).collect(); println!("v4: {:?}", v4); // Method 5: From array let arr = [1, 2, 3, 4, 5]; let v5 = Vec::from(arr); println!("v5: {:?}", v5); // Method 6: with_capacity - pre-allocate space let mut v6 = Vec::with_capacity(10); println!("v6 capacity: {}, length: {}", v6.capacity(), v6.len()); // Method 7: From raw parts (advanced, unsafe) let ptr = Box::into_raw(Box::new([1, 2, 3])) as *mut i32; let v7 = unsafe { Vec::from_raw_parts(ptr, 3, 3) }; println!("v7: {:?}", v7); }

Type Annotations

fn main() { // Explicit type annotation let v1: Vec<i32> = Vec::new(); let v2: Vec<&str> = Vec::new(); let v3: Vec<String> = Vec::new(); // Type inference from usage let mut v4 = Vec::new(); v4.push(42); // Now v4 is Vec<i32> let mut v5 = Vec::new(); v5.push("hello"); // Now v5 is Vec<&str> // Using turbofish syntax let v6 = Vec::<i32>::new(); let v7 = vec![1, 2, 3]; // Vec<i32> inferred // Complex types let v8: Vec<Vec<i32>> = vec![ vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9], ]; println!("v8: {:?}", v8); }

2. Accessing Elements

Indexing and Safe Access

fn main() { let v = vec![10, 20, 30, 40, 50]; // Direct indexing (panics if out of bounds) let third = v[2]; println!("Third element: {}", third); // Safe access with get() (returns Option) match v.get(2) { Some(value) => println!("Third element safely: {}", value), None => println!("No third element"), } // Safe access to non-existent index match v.get(10) { Some(value) => println!("Element at 10: {}", value), None => println!("No element at index 10"), } // First and last elements if let Some(first) = v.first() { println!("First: {}", first); } if let Some(last) = v.last() { println!("Last: {}", last); } // Getting slices let slice = &v[1..4]; // [20, 30, 40] println!("Slice: {:?}", slice); // Getting mutable references let mut v = vec![1, 2, 3, 4, 5]; if let Some(element) = v.get_mut(2) { *element = 100; } println!("After modification: {:?}", v); }

Multiple Element Access

fn main() { let v = vec![1, 2, 3, 4, 5]; // Get multiple elements let first_two = &v[0..2]; println!("First two: {:?}", first_two); // Get all except first let tail = &v[1..]; println!("Tail: {:?}", tail); // Get all except last let init = &v[..v.len()-1]; println!("Init: {:?}", init); // Split into two at index let (left, right) = v.split_at(3); println!("Left: {:?}, Right: {:?}", left, right); // Chunks let chunks: Vec<&[i32]> = v.chunks(2).collect(); println!("Chunks of 2: {:?}", chunks); // Windows (overlapping chunks) let windows: Vec<&[i32]> = v.windows(3).collect(); println!("Windows of 3: {:?}", windows); }

3. Modifying Vectors

Adding Elements

fn main() { // push - add to end let mut v = Vec::new(); v.push(1); v.push(2); v.push(3); println!("After push: {:?}", v); // insert at position v.insert(1, 10); // Insert 10 at index 1 println!("After insert: {:?}", v); // append - move all elements from another vector let mut v2 = vec![4, 5, 6]; v.append(&mut v2); println!("After append: {:?}, v2 empty: {:?}", v, v2); // extend - add elements from iterator v.extend(vec![7, 8, 9]); println!("After extend: {:?}", v); // extend from slice v.extend_from_slice(&[10, 11, 12]); println!("After extend_from_slice: {:?}", v); // reserve space let mut v = Vec::with_capacity(2); println!("Capacity: {}", v.capacity()); v.reserve(10); // Ensure capacity for at least 10 more println!("Capacity after reserve: {}", v.capacity()); }

Removing Elements

fn main() { let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // pop - remove last element if let Some(last) = v.pop() { println!("Popped: {}", last); } println!("After pop: {:?}", v); // remove at index let removed = v.remove(2); // Remove element at index 2 println!("Removed at index 2: {}", removed); println!("After remove: {:?}", v); // remove with swap (doesn't preserve order but O(1)) let mut v = vec![1, 2, 3, 4, 5]; let removed = v.swap_remove(1); // Remove element at index 1, replace with last println!("Swap removed: {}, vector: {:?}", removed, v); // truncate to length let mut v = vec![1, 2, 3, 4, 5]; v.truncate(3); println!("Truncated to 3: {:?}", v); // clear all elements v.clear(); println!("Cleared: {:?}, len: {}", v, v.len()); // drain - remove range let mut v = vec![1, 2, 3, 4, 5]; let drained: Vec<_> = v.drain(1..4).collect(); println!("Drained: {:?}, remaining: {:?}", drained, v); // retain - keep elements satisfying condition let mut v = vec![1, 2, 3, 4, 5, 6]; v.retain(|&x| x % 2 == 0); println!("After retain (evens): {:?}", v); // dedup - remove consecutive duplicates let mut v = vec![1, 1, 2, 2, 3, 1, 1, 4]; v.dedup(); println!("After dedup: {:?}", v); // [1, 2, 3, 1, 4] }

Modifying Elements

fn main() { // Modify by index let mut v = vec![1, 2, 3, 4, 5]; v[2] = 30; println!("After modification: {:?}", v); // Modify using get_mut if let Some(value) = v.get_mut(3) { *value = 40; } println!("After get_mut: {:?}", v); // Swap elements v.swap(0, 4); // Swap first and last println!("After swap: {:?}", v); // Replace with new value, return old let old = std::mem::replace(&mut v[1], 100); println!("Replaced {} with 100, vector: {:?}", old, v); // Update all elements with map in place for x in &mut v { *x *= 2; } println!("After doubling: {:?}", v); // Using resize to change length with default value let mut v = vec![1, 2, 3]; v.resize(5, 0); println!("After resize to 5: {:?}", v); v.resize(2, 0); println!("After resize to 2: {:?}", v); // resize with custom default let mut v = vec!["a", "b", "c"]; v.resize_with(5, || "default"); println!("After resize_with: {:?}", v); }

4. Iterating Over Vectors

Different Iteration Methods

fn main() { let v = vec![10, 20, 30, 40, 50]; // Immutable iteration println!("Immutable iteration:"); for value in &v { print!("{} ", value); } println!(); // Mutable iteration println!("Mutable iteration:"); let mut v = vec![1, 2, 3, 4, 5]; for value in &mut v { *value *= 2; print!("{} ", value); } println!("\nAfter mutation: {:?}", v); // By value (consumes vector) let v = vec![1, 2, 3]; for value in v { print!("{} ", value); } println!(); // println!("{:?}", v); // Error: v moved // With index (enumerate) let v = vec![10, 20, 30]; for (index, value) in v.iter().enumerate() { println!("Index {}: {}", index, value); } // Using iterators explicitly let v = vec![1, 2, 3]; let mut iter = v.iter(); while let Some(value) = iter.next() { println!("Iterator next: {}", value); } }

Functional Iteration

fn main() { let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // map let doubled: Vec<_> = numbers.iter().map(|&x| x * 2).collect(); println!("Doubled: {:?}", doubled); // filter let evens: Vec<_> = numbers.iter().filter(|&&x| x % 2 == 0).collect(); println!("Evens: {:?}", evens); // filter_map let strings = vec!["1", "2", "abc", "3", "def"]; let parsed: Vec<i32> = strings.iter() .filter_map(|s| s.parse().ok()) .collect(); println!("Parsed numbers: {:?}", parsed); // fold (reduce) let sum = numbers.iter().fold(0, |acc, &x| acc + x); println!("Sum: {}", sum); // any and all let has_even = numbers.iter().any(|&x| x % 2 == 0); let all_positive = numbers.iter().all(|&x| x > 0); println!("Has even: {}, All positive: {}", has_even, all_positive); // find and position if let Some(first_even) = numbers.iter().find(|&&x| x % 2 == 0) { println!("First even: {}", first_even); } if let Some(pos) = numbers.iter().position(|&x| x == 5) { println!("5 at position: {}", pos); } // min and max println!("Min: {:?}", numbers.iter().min()); println!("Max: {:?}", numbers.iter().max()); // chain operations let result: i32 = numbers.iter() .filter(|&&x| x % 2 == 0) .map(|&x| x * x) .take(3) .sum(); println!("Sum of first 3 even squares: {}", result); }

5. Vector Capacity and Performance

Understanding Capacity

fn main() { // Capacity vs length let mut v = Vec::with_capacity(10); println!("Initial - len: {}, cap: {}", v.len(), v.capacity()); for i in 0..5 { v.push(i); println!("After push {} - len: {}, cap: {}", i, v.len(), v.capacity()); } // When capacity is exceeded, vector reallocates for i in 5..15 { v.push(i); println!("After push {} - len: {}, cap: {}", i, v.len(), v.capacity()); } // Shrink to fit v.shrink_to_fit(); println!("After shrink - len: {}, cap: {}", v.len(), v.capacity()); // Reserve additional capacity v.reserve(100); println!("After reserve 100 - cap: {}", v.capacity()); // Reserve exact capacity v.reserve_exact(50); println!("After reserve_exact 50 - cap: {}", v.capacity()); }

Performance Comparisons

use std::time::Instant; fn main() { // Pre-allocation vs dynamic growth const SIZE: usize = 100_000; // Without pre-allocation let start = Instant::now(); let mut v1 = Vec::new(); for i in 0..SIZE { v1.push(i); } println!("Without pre-allocation: {:?}", start.elapsed()); // With pre-allocation let start = Instant::now(); let mut v2 = Vec::with_capacity(SIZE); for i in 0..SIZE { v2.push(i); } println!("With pre-allocation: {:?}", start.elapsed()); // Index access vs get() let v = vec![0; SIZE]; let start = Instant::now(); for i in 0..SIZE { let _ = v[i]; } println!("Direct indexing: {:?}", start.elapsed()); let start = Instant::now(); for i in 0..SIZE { let _ = v.get(i); } println!("get() method: {:?}", start.elapsed()); // Iteration methods let start = Instant::now(); let mut sum = 0; for i in 0..SIZE { sum += v[i]; } println!("Manual index loop: {:?}", start.elapsed()); let start = Instant::now(); let mut sum = 0; for &x in &v { sum += x; } println!("Iterator loop: {:?}", start.elapsed()); }

6. Working with Different Types

Vectors of Custom Types

#[derive(Debug, Clone)] struct Person { name: String, age: u32, } #[derive(Debug)] struct Point { x: f64, y: f64, } impl Point { fn new(x: f64, y: f64) -> Self { Point { x, y } } fn distance(&self, other: &Point) -> f64 { let dx = self.x - other.x; let dy = self.y - other.y; (dx * dx + dy * dy).sqrt() } } fn main() { // Vector of structs let people = vec![ Person { name: "Alice".to_string(), age: 30 }, Person { name: "Bob".to_string(), age: 25 }, Person { name: "Charlie".to_string(), age: 35 }, ]; for person in &people { println!("{:?}", person); } // Vector of Points let points = vec![ Point::new(0.0, 0.0), Point::new(3.0, 4.0), Point::new(1.0, 1.0), ]; let origin = &points[0]; for point in &points[1..] { println!("Distance from origin: {}", origin.distance(point)); } // Sorting custom types (need PartialOrd) let mut people = people; people.sort_by(|a, b| a.age.cmp(&b.age)); println!("Sorted by age: {:?}", people); // Vector of enums (heterogeneous data) #[derive(Debug)] enum Value { Int(i32), Float(f64), Text(String), } let mixed = vec![ Value::Int(42), Value::Float(3.14), Value::Text("hello".to_string()), Value::Int(100), ]; for value in &mixed { match value { Value::Int(x) => println!("Int: {}", x), Value::Float(x) => println!("Float: {}", x), Value::Text(s) => println!("Text: {}", s), } } }

Vectors of References

fn main() { // Vector of references let x = 10; let y = 20; let z = 30; let refs = vec![&x, &y, &z]; for &&val in &refs { println!("Referenced value: {}", val); } // Vector of references to strings let strings = vec![ String::from("hello"), String::from("world"), String::from("!"), ]; let refs: Vec<&String> = strings.iter().collect(); for s in refs { println!("{}", s); } // Vector of boxed values let boxed: Vec<Box<i32>> = vec![Box::new(1), Box::new(2), Box::new(3)]; for b in &boxed { println!("Boxed: {}", **b); } // Vector of trait objects trait Animal { fn speak(&self); } struct Dog; struct Cat; impl Animal for Dog { fn speak(&self) { println!("Woof!"); } } impl Animal for Cat { fn speak(&self) { println!("Meow!"); } } let animals: Vec<Box<dyn Animal>> = vec![ Box::new(Dog), Box::new(Cat), Box::new(Dog), ]; for animal in &animals { animal.speak(); } }

7. Vector Slices and Views

Working with Slices

fn main() { let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Create slices let slice1 = &v[2..5]; // [3, 4, 5] let slice2 = &v[..4]; // [1, 2, 3, 4] let slice3 = &v[6..]; // [7, 8, 9, 10] let slice4 = &v[..]; // entire vector println!("slice1: {:?}", slice1); println!("slice2: {:?}", slice2); println!("slice3: {:?}", slice3); // Functions that work with slices fn sum_slice(slice: &[i32]) -> i32 { slice.iter().sum() } println!("Sum of slice1: {}", sum_slice(slice1)); println!("Sum of v: {}", sum_slice(&v)); // Mutable slices let mut v = vec![1, 2, 3, 4, 5]; let slice = &mut v[2..4]; slice[0] = 30; slice[1] = 40; println!("Modified v: {:?}", v); // Split into slices let (left, right) = v.split_at_mut(3); left[0] = 10; right[0] = 50; println!("After split: {:?}", v); }

Converting Between Vectors and Slices

fn main() { // Vector to slice let v = vec![1, 2, 3, 4, 5]; let slice: &[i32] = &v; // Slice to vector let arr = [1, 2, 3, 4, 5]; let v_from_slice: Vec<i32> = arr.to_vec(); let v_from_slice2 = Vec::from(&arr[1..4]); println!("v_from_slice: {:?}", v_from_slice); println!("v_from_slice2: {:?}", v_from_slice2); // as_slice and as_mut_slice let mut v = vec![1, 2, 3]; let s = v.as_slice(); println!("as_slice: {:?}", s); let s_mut = v.as_mut_slice(); s_mut[0] = 10; println!("After as_mut_slice: {:?}", v); // Converting between types let v: Vec<i32> = (0..5).collect(); let boxed_slice: Box<[i32]> = v.into_boxed_slice(); let v_back: Vec<i32> = boxed_slice.into_vec(); println!("Back to vector: {:?}", v_back); }

8. Common Vector Operations

Searching and Finding

fn main() { let v = vec![1, 2, 3, 4, 5, 3, 2, 1]; // Contains let has_three = v.contains(&3); println!("Contains 3: {}", has_three); // Find index of first occurrence if let Some(pos) = v.iter().position(|&x| x == 3) { println!("First 3 at position: {}", pos); } // Find index of last occurrence if let Some(pos) = v.iter().rposition(|&x| x == 3) { println!("Last 3 at position: {}", pos); } // Find element if let Some(&element) = v.iter().find(|&&x| x > 3) { println!("First element > 3: {}", element); } // Binary search (requires sorted vector) let mut sorted = v.clone(); sorted.sort(); match sorted.binary_search(&3) { Ok(pos) => println!("3 found at position {} in sorted", pos), Err(pos) => println!("3 not found, would be at position {}", pos), } // Check if all elements satisfy condition let all_positive = v.iter().all(|&x| x > 0); println!("All positive: {}", all_positive); // Check if any element satisfies condition let any_even = v.iter().any(|&x| x % 2 == 0); println!("Any even: {}", any_even); }

Sorting and Ordering

fn main() { let mut numbers = vec![5, 2, 8, 1, 9, 3, 7, 4, 6]; // Sort in ascending order numbers.sort(); println!("Ascending: {:?}", numbers); // Sort in descending order numbers.sort_by(|a, b| b.cmp(a)); println!("Descending: {:?}", numbers); // Sort with custom comparator let mut people = vec![ ("Alice", 30), ("Bob", 25), ("Charlie", 35), ("Alice", 20), ]; people.sort_by(|a, b| { a.0.cmp(&b.0).then(a.1.cmp(&b.1)) }); println!("Sorted people: {:?}", people); // Partial sort (only sort part of the vector) let mut v = vec![5, 2, 8, 1, 9, 3, 7, 4, 6]; v.sort_unstable(); // Faster but doesn't preserve order of equal elements println!("Unstable sort: {:?}", v); // Reverse let mut v = vec![1, 2, 3, 4, 5]; v.reverse(); println!("Reversed: {:?}", v); // Rotate v.rotate_left(2); println!("Rotated left by 2: {:?}", v); v.rotate_right(1); println!("Rotated right by 1: {:?}", v); }

Combining Vectors

fn main() { // Concatenation let v1 = vec![1, 2, 3]; let v2 = vec![4, 5, 6]; // Method 1: extend let mut v3 = v1.clone(); v3.extend(v2.clone()); println!("Extended: {:?}", v3); // Method 2: chain let v4: Vec<_> = v1.iter().chain(v2.iter()).cloned().collect(); println!("Chained: {:?}", v4); // Method 3: append (moves) let mut v5 = v1.clone(); let mut v6 = v2.clone(); v5.append(&mut v6); println!("Appended: {:?}, v6 empty: {:?}", v5, v6); // Join (for vectors of strings) let strings = vec!["hello", "world", "!"]; let joined = strings.join(" "); println!("Joined: '{}'", joined); // Split let numbers = vec![1, 2, 3, 4, 5, 6]; let (first, second): (Vec<_>, Vec<_>) = numbers.iter() .partition(|&&x| x < 4); println!("First partition: {:?}, Second: {:?}", first, second); // Zip let names = vec!["Alice", "Bob", "Charlie"]; let ages = vec![30, 25, 35]; let zipped: Vec<_> = names.iter().zip(ages.iter()).collect(); println!("Zipped: {:?}", zipped); }

9. Advanced Vector Techniques

Vector as Stack

fn main() { let mut stack: Vec<i32> = Vec::new(); // Push onto stack stack.push(1); stack.push(2); stack.push(3); println!("Stack: {:?}", stack); // Pop from stack while let Some(top) = stack.pop() { println!("Popped: {}", top); } // Using as stack with capacity let mut stack = Vec::with_capacity(5); for i in 0..5 { stack.push(i); println!("Push {}, len: {}, cap: {}", i, stack.len(), stack.capacity()); } // Peek at top without popping if let Some(top) = stack.last() { println!("Top: {}", top); } // Stack operations fn evaluate_postfix(expression: &str) -> Option<i32> { let mut stack = Vec::new(); for token in expression.split_whitespace() { match token.parse::<i32>() { Ok(num) => stack.push(num), Err(_) => { let b = stack.pop()?; let a = stack.pop()?; match token { "+" => stack.push(a + b), "-" => stack.push(a - b), "*" => stack.push(a * b), "/" => stack.push(a / b), _ => return None, } } } } stack.pop() } let result = evaluate_postfix("3 4 + 2 *"); println!("Postfix result: {:?}", result); // (3+4)*2 = 14 }

Vector as Queue

use std::collections::VecDeque; fn main() { // VecDeque is better for queue operations let mut queue = VecDeque::new(); // Add to back queue.push_back(1); queue.push_back(2); queue.push_back(3); println!("Queue: {:?}", queue); // Add to front queue.push_front(0); println!("After push_front: {:?}", queue); // Remove from front while let Some(front) = queue.pop_front() { println!("Processing: {}", front); } // Using Vec as queue (less efficient) let mut queue_vec = Vec::new(); queue_vec.push(1); queue_vec.push(2); queue_vec.push(3); while !queue_vec.is_empty() { let front = queue_vec.remove(0); // O(n) operation! println!("Processing (Vec): {}", front); } // Ring buffer with VecDeque let mut buffer = VecDeque::with_capacity(5); for i in 0..10 { if buffer.len() == 5 { buffer.pop_front(); } buffer.push_back(i); println!("Buffer: {:?}", buffer); } }

Matrix Operations with Vectors

#[derive(Debug)] struct Matrix { data: Vec<Vec<i32>>, rows: usize, cols: usize, } impl Matrix { fn new(rows: usize, cols: usize) -> Self { Matrix { data: vec![vec![0; cols]; rows], rows, cols, } } fn from_vec(data: Vec<Vec<i32>>) -> Option<Self> { if data.is_empty() { return None; } let rows = data.len(); let cols = data[0].len(); // Check if all rows have same length if data.iter().any(|row| row.len() != cols) { return None; } Some(Matrix { data, rows, cols, }) } fn get(&self, row: usize, col: usize) -> Option<&i32> { if row < self.rows && col < self.cols { Some(&self.data[row][col]) } else { None } } fn set(&mut self, row: usize, col: usize, value: i32) -> Option<()> { if row < self.rows && col < self.cols { self.data[row][col] = value; Some(()) } else { None } } fn transpose(&self) -> Matrix { let mut result = Matrix::new(self.cols, self.rows); for i in 0..self.rows { for j in 0..self.cols { result.data[j][i] = self.data[i][j]; } } result } fn multiply(&self, other: &Matrix) -> Option<Matrix> { if self.cols != other.rows { return None; } let mut result = Matrix::new(self.rows, other.cols); for i in 0..self.rows { for j in 0..other.cols { let mut sum = 0; for k in 0..self.cols { sum += self.data[i][k] * other.data[k][j]; } result.data[i][j] = sum; } } Some(result) } } fn main() { let mut mat = Matrix::new(3, 3); // Fill matrix for i in 0..3 { for j in 0..3 { mat.set(i, j, (i * 3 + j + 1) as i32).unwrap(); } } println!("Original matrix: {:?}", mat); // Get element if let Some(val) = mat.get(1, 1) { println!("Element at (1,1): {}", val); } // Transpose let transposed = mat.transpose(); println!("Transposed: {:?}", transposed); // Matrix multiplication let mat2 = Matrix::new(3, 3); if let Some(product) = mat.multiply(&mat2) { println!("Product: {:?}", product); } }

10. Error Handling with Vectors

Safe Access Patterns

fn main() { let v = vec![1, 2, 3, 4, 5]; // Safe indexing with match match v.get(10) { Some(value) => println!("Value: {}", value), None => println!("Index out of bounds"), } // Safe indexing with if let if let Some(value) = v.get(2) { println!("Found: {}", value); } // Using unwrap_or for defaults let value = v.get(10).unwrap_or(&-1); println!("Default value: {}", value); // Custom error type #[derive(Debug)] enum VecError { IndexOutOfBounds(usize, usize), EmptyVector, } fn safe_first<T>(v: &[T]) -> Result<&T, VecError> { v.first().ok_or(VecError::EmptyVector) } fn safe_get<T>(v: &[T], index: usize) -> Result<&T, VecError> { v.get(index).ok_or(VecError::IndexOutOfBounds(index, v.len())) } match safe_get(&v, 10) { Ok(val) => println!("Got: {}", val), Err(VecError::IndexOutOfBounds(idx, len)) => { println!("Index {} out of bounds for length {}", idx, len); } Err(VecError::EmptyVector) => println!("Vector is empty"), } // Try operations fn try_operations(v: &[i32]) -> Option<i32> { let first = v.first()?; let last = v.last()?; Some(first + last) } if let Some(sum) = try_operations(&v) { println!("Sum of first and last: {}", sum); } }

Fallible Vector Operations

use std::num::ParseIntError; fn main() { // Collecting Results let strings = vec!["1", "2", "abc", "3", "def"]; // Collect into Result<Vec<i32>, ParseIntError> let parsed: Result<Vec<i32>, ParseIntError> = strings .iter() .map(|s| s.parse::<i32>()) .collect(); match parsed { Ok(numbers) => println!("All parsed: {:?}", numbers), Err(e) => println!("Error parsing: {}", e), } // Filter out errors let successful: Vec<i32> = strings .iter() .filter_map(|s| s.parse().ok()) .collect(); println!("Successful: {:?}", successful); // Partition results let (successes, failures): (Vec<_>, Vec<_>) = strings .iter() .map(|s| s.parse::<i32>()) .partition(Result::is_ok); let successes: Vec<_> = successes.into_iter().map(Result::unwrap).collect(); let failures: Vec<_> = failures.into_iter().map(Result::unwrap_err).collect(); println!("Successes: {:?}", successes); println!("Failures: {:?}", failures); // Try fold for early termination let numbers = vec![1, 2, 3, 4, 5]; let result = numbers.iter().try_fold(0, |acc, &x| { if x == 3 { None } else { Some(acc + x) } }); match result { Some(sum) => println!("Sum until 3: {}", sum), None => println!("Stopped at 3"), } }

11. Parallel Processing with Vectors

Using Rayon for Parallel Iteration

// Add rayon = "1.7" to Cargo.toml use rayon::prelude::*; fn main() { let numbers: Vec<i32> = (0..1_000_000).collect(); // Parallel map let start = std::time::Instant::now(); let squares: Vec<i32> = numbers.par_iter() .map(|&x| x * x) .collect(); println!("Parallel map time: {:?}", start.elapsed()); // Parallel filter let evens: Vec<&i32> = numbers.par_iter() .filter(|&&x| x % 2 == 0) .collect(); println!("Found {} evens", evens.len()); // Parallel fold let sum: i32 = numbers.par_iter() .fold(|| 0, |acc, &x| acc + x) .sum(); println!("Parallel sum: {}", sum); // Parallel any/all let has_negative = numbers.par_iter().any(|&x| x < 0); let all_positive = numbers.par_iter().all(|&x| x >= 0); println!("Has negative: {}, All positive: {}", has_negative, all_positive); // Parallel find if let Some(first_even) = numbers.par_iter().find_first(|&&x| x % 2 == 0) { println!("First even: {}", first_even); } // Parallel sort (rayon doesn't have parallel sort, but we can use par_sort) let mut unsorted: Vec<i32> = (0..100_000).rev().collect(); unsorted.par_sort(); // Uses rayon's parallel sort println!("First few after sort: {:?}", &unsorted[..5]); }

12. Common Patterns and Best Practices

Builder Pattern with Vectors

#[derive(Debug, Clone)] struct QueryBuilder { select: Vec<String>, from: String, where_clauses: Vec<String>, order_by: Vec<(String, bool)>, // (column, ascending) limit: Option<usize>, } impl QueryBuilder { fn new(table: &str) -> Self { QueryBuilder { select: vec!["*".to_string()], from: table.to_string(), where_clauses: Vec::new(), order_by: Vec::new(), limit: None, } } fn select(mut self, columns: Vec<&str>) -> Self { self.select = columns.into_iter().map(String::from).collect(); self } fn and_where(mut self, condition: &str) -> Self { self.where_clauses.push(condition.to_string()); self } fn order_by(mut self, column: &str, ascending: bool) -> Self { self.order_by.push((column.to_string(), ascending)); self } fn limit(mut self, limit: usize) -> Self { self.limit = Some(limit); self } fn build(&self) -> String { let select_str = if self.select.len() == 1 && self.select[0] == "*" { "*".to_string() } else { self.select.join(", ") }; let mut query = format!("SELECT {} FROM {}", select_str, self.from); if !self.where_clauses.is_empty() { query.push_str(" WHERE "); query.push_str(&self.where_clauses.join(" AND ")); } if !self.order_by.is_empty() { let order_str: Vec<String> = self.order_by .iter() .map(|(col, asc)| format!("{} {}", col, if *asc { "ASC" } else { "DESC" })) .collect(); query.push_str(" ORDER BY "); query.push_str(&order_str.join(", ")); } if let Some(limit) = self.limit { query.push_str(&format!(" LIMIT {}", limit)); } query } } fn main() { let query = QueryBuilder::new("users") .select(vec!["id", "name", "email"]) .and_where("age > 18") .and_where("active = true") .order_by("name", true) .limit(10) .build(); println!("{}", query); }

Pool Pattern with Vectors

struct ObjectPool<T> { objects: Vec<T>, max_size: usize, } impl<T> ObjectPool<T> { fn new(max_size: usize) -> Self { ObjectPool { objects: Vec::with_capacity(max_size), max_size, } } fn acquire(&mut self) -> Option<T> { self.objects.pop() } fn release(&mut self, obj: T) -> Result<(), T> { if self.objects.len() < self.max_size { self.objects.push(obj); Ok(()) } else { Err(obj) // Pool full } } fn with_capacity(capacity: usize, f: impl Fn() -> T) -> Self { let mut objects = Vec::with_capacity(capacity); for _ in 0..capacity { objects.push(f()); } ObjectPool { objects, max_size: capacity, } } } #[derive(Debug)] struct Connection { id: usize, connected: bool, } impl Connection { fn new(id: usize) -> Self { Connection { id, connected: true, } } fn query(&self, sql: &str) { println!("Connection {} executing: {}", self.id, sql); } } fn main() { let mut pool = ObjectPool::with_capacity(3, || Connection::new(rand::random())); // Acquire connections if let Some(mut conn) = pool.acquire() { conn.query("SELECT * FROM users"); // Release back to pool let _ = pool.release(conn); } // Pool full example for i in 0..5 { let conn = Connection::new(i); match pool.release(conn) { Ok(()) => println!("Connection {} added to pool", i), Err(conn) => println!("Pool full, connection {} dropped", conn.id), } } }

13. Testing and Documentation

Testing Vector Operations

#[cfg(test)] mod tests { #[test] fn test_vector_creation() { let v1 = vec![1, 2, 3]; assert_eq!(v1.len(), 3); assert_eq!(v1[0], 1); let v2: Vec<i32> = (0..5).collect(); assert_eq!(v2, vec![0, 1, 2, 3, 4]); } #[test] fn test_vector_operations() { let mut v = vec![1, 2, 3]; v.push(4); assert_eq!(v, vec![1, 2, 3, 4]); let last = v.pop(); assert_eq!(last, Some(4)); assert_eq!(v, vec![1, 2, 3]); v.insert(1, 10); assert_eq!(v, vec![1, 10, 2, 3]); } #[test] fn test_vector_iteration() { let v = vec![1, 2, 3]; let sum: i32 = v.iter().sum(); assert_eq!(sum, 6); let doubled: Vec<i32> = v.iter().map(|&x| x * 2).collect(); assert_eq!(doubled, vec![2, 4, 6]); } #[test] #[should_panic(expected = "index out of bounds")] fn test_out_of_bounds() { let v = vec![1, 2, 3]; let _ = v[5]; // This panics } #[test] fn test_safe_access() { let v = vec![1, 2, 3]; assert_eq!(v.get(5), None); assert_eq!(v.get(1), Some(&2)); } }

Documentation Examples

/// A custom vector wrapper with additional functionality /// /// # Examples /// /// ``` /// use mylib::MyVec; /// /// let mut v = MyVec::new(); /// v.push(1); /// v.push(2); /// v.push(3); /// /// assert_eq!(v.sum(), 6); /// assert_eq!(v.average(), 2.0); /// ``` #[derive(Debug, Clone)] pub struct MyVec<T> { data: Vec<T>, } impl<T> MyVec<T> { /// Creates a new empty `MyVec` pub fn new() -> Self { MyVec { data: Vec::new() } } /// Adds an element to the vector /// /// # Examples /// /// ``` /// let mut v = MyVec::new(); /// v.push(42); /// assert_eq!(v.len(), 1); /// ``` pub fn push(&mut self, value: T) { self.data.push(value); } /// Returns the number of elements pub fn len(&self) -> usize { self.data.len() } /// Returns true if the vector is empty pub fn is_empty(&self) -> bool { self.data.is_empty() } } impl MyVec<i32> { /// Returns the sum of all elements /// /// # Panics /// /// Panics if the vector is empty pub fn sum(&self) -> i32 { self.data.iter().sum() } /// Returns the average of all elements /// /// # Panics /// /// Panics if the vector is empty pub fn average(&self) -> f64 { self.sum() as f64 / self.len() as f64 } } impl<T> Default for MyVec<T> { fn default() -> Self { Self::new() } }

Conclusion

Vectors are one of the most versatile and commonly used collections in Rust:

Key Takeaways

  1. Dynamic sizing: Vectors grow and shrink at runtime
  2. Memory efficient: Elements stored contiguously
  3. Fast access: O(1) index access
  4. Ownership: Vector owns its elements
  5. Rich API: Extensive set of methods for manipulation
  6. Performance: Control over capacity for optimization

Common Operations Summary

OperationMethodTime Complexity
Create emptyVec::new()O(1)
Create with valuesvec![1, 2, 3]O(n)
Add to endpush()O(1) amortized
Remove from endpop()O(1)
Insert at indexinsert()O(n)
Remove at indexremove()O(n)
Get elementget()O(1)
Iterateiter()O(n)
Find elementposition()O(n)
Sortsort()O(n log n)

Best Practices

  1. Pre-allocate capacity when you know the size in advance
  2. Use get() for safe indexing instead of direct indexing
  3. Prefer iterators over manual indexing when possible
  4. Use Vec::with_capacity() for performance-critical code
  5. Consider VecDeque if you need to add/remove from both ends
  6. Use shrink_to_fit() to free unused memory
  7. Be mindful of ownership when passing vectors to functions

Vectors are fundamental to Rust programming and mastering them is essential for writing efficient and idiomatic Rust code.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper