Chapter 22: Rust Data Structures
Rust Data Structures.
When people say “Rust Data Structures” in learning context, they usually mean two overlapping things:
- The built-in / primitive compound types that come with the language (tuples, arrays, slices)
- The collections from the standard library that almost every real Rust program uses (Vec, String, HashMap, HashSet, BTreeMap, etc.)
Rust is deliberately minimal in the language itself — it gives you very few built-in data structures, but the standard library collections are excellent, safe, and performant. Most of the time when you need a “data structure”, you reach for std::vec, std::collections, or crates like hashbrown, arrayvec, smallvec, etc.
Today I’ll teach both layers like your patient teacher sitting next to you: slowly, with lots of runnable examples, clear analogies, comparisons to other languages, and practical patterns you’ll see in real 2025–2026 Rust code.
Layer 1 — Built-in / Primitive Data Structures (Language Level)
These are part of the Rust syntax — no use needed.
1. Tuple — Fixed-size, heterogeneous grouping
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
fn main() { // (type1, type2, type3) let person: (String, u32, bool) = (String::from("Webliance"), 25, true); // Access by index println!("Name: {}, Age: {}, Active: {}", person.0, person.1, person.2); // Destructuring (very common & clean) let (name, age, is_active) = person; println!("Destructured → {} is {} years old", name, age); // Unit tuple () = "nothing" / void let nothing = (); } |
Use case: returning multiple values from functions, fixed config pairs.
2. Array — Fixed-size, same-type, stack-allocated
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
fn main() { // [T; N] — size known at compile time let temperatures: [f32; 7] = [28.5, 30.0, 32.1, 29.8, 31.2, 33.0, 34.5]; println!("Monday temp: {}°C", temperatures[0]); println!("Length: {}", temperatures.len()); // 7 // All same value shorthand let zeros = [0u8; 1024]; // 1024 bytes of zero — fast & stack // Iterate for temp in temperatures { println!("Temp: {}", temp); } } |
- Fast, no heap allocation
- Size part of the type — [i32; 5] ≠ [i32; 6]
- Cannot grow/shrink → use Vec when size is dynamic
3. Slice — View / reference into array / Vec / String
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
fn main() { let arr = [10, 20, 30, 40, 50]; // Slice of whole array let full: &[i32] = &arr[..]; // Sub-slice let middle = &arr[1..4]; // 20, 30, 40 println!("Middle: {:?}", middle); // Mutable slice let mut numbers = [1, 2, 3]; let slice = &mut numbers[0..2]; slice[0] = 100; println!("{:?}", numbers); // [100, 2, 3] } |
- Type: &[T] or &mut [T]
- Very common in function parameters (like &str is actually &[u8] with UTF-8 guarantee)
Layer 2 — Standard Library Collections (What You Use Every Day)
You need use std::collections::*; or specific imports.
1. Vec<T> — Growable, dynamic array (most used collection)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
fn main() { // Create let mut scores = Vec::new(); // empty let mut cities = vec!["Hyderabad", "Warangal", "Nizamabad"]; // Add elements scores.push(85); scores.push(92); scores.extend_from_slice(&[78, 95]); // Access println!("First score: {}", scores[0]); println!("Last city: {}", cities.last().unwrap()); // Iterate & mutate for city in &mut cities { *city = city.to_uppercase(); } println!("Uppercase cities: {:?}", cities); // Remove cities.pop(); // remove last cities.remove(0); // remove at index 0 } |
- Heap-allocated, grows automatically
- Like Python list / Java ArrayList / C++ vector
2. String (already covered, but recap as collection)
|
0 1 2 3 4 5 6 7 8 |
let mut s = String::with_capacity(100); s.push_str("Namaste "); s += "Hyderabad!"; |
3. HashMap<K, V> — Hash table / dictionary
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
use std::collections::HashMap; fn main() { let mut scores = HashMap::new(); scores.insert(String::from("Webliance"), 95); scores.insert(String::from("Friend1"), 82); // Access if let Some(score) = scores.get("Webliance") { println!("Score: {}", score); } // Iterate for (name, score) in &scores { println!("{} → {}", name, score); } // Update or insert scores.entry(String::from("NewPlayer")).or_insert(0); *scores.entry(String::from("Webliance")).or_insert(0) += 5; } |
- Keys must implement Eq + Hash
- Common keys: String, &str (with .to_string() or String::from)
4. HashSet<T> — Unique unordered collection
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
use std::collections::HashSet; fn main() { let mut unique_cities = HashSet::new(); unique_cities.insert("Hyderabad"); unique_cities.insert("Hyderabad"); // ignored — duplicate unique_cities.insert("Secunderabad"); println!("Unique: {:?}", unique_cities); println!("Contains Hyderabad? {}", unique_cities.contains("Hyderabad")); } |
5. BTreeMap<K, V> & BTreeSet<T> — Sorted / ordered versions
Use when you need keys sorted (e.g. leaderboard).
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
use std::collections::BTreeMap; let mut leaderboard = BTreeMap::new(); leaderboard.insert(95, "Webliance"); leaderboard.insert(82, "Friend1"); // Iterates in sorted order (by key) for (score, name) in &leaderboard { println!("{} → {}", score, name); } |
Quick Comparison Table (2026 Style)
| Structure | Growable? | Ordered? | Access | Best For | Heap? |
|---|---|---|---|---|---|
| [T; N] | No | Yes | Index | Fixed small data, stack fast | No |
| &[T] | No | Yes | Index | Function params, views | No |
| Vec<T> | Yes | Yes | Index | Most dynamic lists | Yes |
| String | Yes | Yes | — | Mutable text | Yes |
| HashMap<K,V> | Yes | No | Key | Fast lookup by key | Yes |
| BTreeMap<K,V> | Yes | Yes | Key | Sorted keys, range queries | Yes |
| HashSet<T> | Yes | No | Contains | Uniqueness, membership | Yes |
Practice Project Suggestion
|
0 1 2 3 4 5 6 7 |
cargo new rust_data_structures cd rust_data_structures |
Try to build:
- Vec<u32> of temperatures → find max/min/average
- HashMap<String, u32> of city → population
- HashSet<String> of favorite foods (add duplicates → see uniqueness)
- Function that takes slice &[i32] and returns sum
Want next?
- Iterators in depth (.map, .filter, .collect — huge in Rust)?
- Custom structs + how they work with ownership/borrowing?
- Enums + pattern matching on data structures?
- Or common crates for more advanced structures (smallvec, arrayvec, indexmap)?
Just tell me — your Rust class from Hyderabad is going strong! 🦀🚀
