What Are Collections in Rust?
Collections are data structures that store multiple values. Unlike fixed-size arrays, collections are dynamic and can grow or shrink as needed. Rust provides several commonly used collections:
- Vec<T> (Vector)
- String
- HashMap<K, V>
- HashSet<T>
- VecDeque<T>
- LinkedList<T>
- BinaryHeap<T>
Each collection is optimized for specific use cases, and selecting the right one is crucial for performance.
1. Vec<T>: The Vector
The vector is one of the most commonly used collections. It is a resizable array that stores elements of the same type.
Key Features
- Stores elements in a contiguous memory block.
- Allows indexing.
- Can dynamically grow or shrink.
Example: Basic Vector Usage
fn main() {
let mut numbers: Vec<i32> = Vec::new(); // Create an empty vector
numbers.push(10); // Add elements
numbers.push(20);
numbers.push(30);
println!("{:?}", numbers); // Output: [10, 20, 30]
numbers.pop(); // Remove the last element
println!("{:?}", numbers); // Output: [10, 20]
for num in &numbers {
println!("{}", num); // Iterate over elements
}
}
2. String: Owned String Type
The String collection is used for dynamically growing, heap-allocated strings.
Key Features
- Stores UTF-8 encoded text.
- Can grow dynamically.
- Provides extensive methods for string manipulation.
Example: String Operations
fn main() {
let mut greeting = String::from("Hello");
greeting.push_str(", world!"); // Append a string
println!("{}", greeting); // Output: Hello, world!
greeting.replace_range(0..5, "Hi"); // Replace part of the string
println!("{}", greeting); // Output: Hi, world!
}
3. HashMap<K, V>: Key-Value Store
The HashMap stores key-value pairs, where keys are unique.
Key Features
- Provides fast lookup and insertion.
- Keys must implement the Eq and Hash traits.
Example: Using HashMap
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 50);
scores.insert("Bob", 40);
// Access a value
if let Some(score) = scores.get("Alice") {
println!("Alice's score: {}", score);
}
// Iterate through key-value pairs
for (key, value) in &scores {
println!("{}: {}", key, value);
}
}
4. HashSet<T>: Unique Values
The HashSet ensures that all elements are unique.
Key Features
- Does not allow duplicate values.
- Provides set operations like union, intersection, and difference.
Example: Using HashSet
use std::collections::HashSet;
fn main() {
let mut fruits = HashSet::new();
fruits.insert("Apple");
fruits.insert("Banana");
fruits.insert("Apple"); // Duplicate, ignored
println!("{:?}", fruits); // Output: {"Apple", "Banana"}
}
5. VecDeque<T>: Double-Ended Queue
The VecDeque
supports efficient addition and removal of elements from both ends.
Key Features
- Useful for queues or deques.
- More efficient than Vec for operations at both ends.
Example: Using VecDeque
use std::collections::VecDeque;
fn main() {
let mut deque = VecDeque::new();
deque.push_back(1);
deque.push_front(0);
println!("{:?}", deque); // Output: [0, 1]
}
6. LinkedList<T>: Doubly Linked List
The LinkedList provides sequential storage using nodes connected by pointers.
Key Features
- Good for frequent insertions and deletions in the middle.
- Slower for random access compared to
Vec
.
Example: Using LinkedList
use std::collections::LinkedList;
fn main() {
let mut list = LinkedList::new();
list.push_back(1);
list.push_front(0);
println!("{:?}", list); // Output: [0, 1]
}
7. BinaryHeap<T>: Priority Queue
The BinaryHeap is a max-heap by default, useful for implementing priority queues.
Key Features
- Efficient for retrieving the maximum element.
- Automatically maintains heap order.
Example: Using BinaryHeap
use std::collections::BinaryHeap;
fn main() {
let mut heap = BinaryHeap::new();
heap.push(4);
heap.push(7);
heap.push(1);
println!("{:?}", heap.pop()); // Output: Some(7) (max element)
}
Choosing the Right Collection
Collection | Use Case |
---|---|
Vec<T> | When you need a dynamic, indexed list. |
String | When you need a dynamically growable text. |
HashMap<K, V> | When you need a key-value store for fast lookup. |
HashSet<T> | When you need a collection of unique items. |
VecDeque<T> | When you need efficient additions/removals at both ends. |
LinkedList<T> | When frequent insertions/deletions in the middle are required. |
BinaryHeap<T> | When you need to maintain priority or retrieve the max/min element. |