Chapter 24: Rust Arrays
Rust Arrays.
Rust arrays are one of the simplest but also one of the most strict data structures in the language. They are very different from arrays in Python, JavaScript or even C in some ways — and understanding them properly helps you later when you move to slices, Vec, and borrowing.
Let me explain Rust arrays like your patient teacher sitting next to you with VS Code open: slowly, clearly, with many small examples you can copy-paste and run right now, everyday Hyderabad analogies, comparisons to other languages, and all the important details step by step.
1. What is an Array in Rust? (The Core Idea)
In Rust, an array is:
- Fixed-size collection of elements of the same type
- Size is known at compile time and part of the type
- Stored on the stack (very fast, no heap allocation)
- Syntax: [T; N] where T = element type, N = exact number of elements
Example:
|
0 1 2 3 4 5 6 |
let temperatures: [f32; 7] = [28.5, 30.0, 32.1, 29.8, 31.2, 33.0, 34.5]; |
- Type = [f32; 7]
- You cannot add or remove elements after creation
- You cannot have an array of size 5 and assign it to a variable that expects size 6 — compiler error!
2. Creating Arrays – All the Common Ways
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
fn main() { // Way 1: List all values let days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]; // Way 2: All elements the same value (very fast & common) let zeros = [0i32; 100]; // 100 zeros let buffers = [false; 1024]; // 1 KB of false flags // Way 3: Repeat expression (Rust 1.56+) let squares = [0; 10]; // still zeros // let squares = [i * i; 10]; // ERROR — not const expression println!("First day: {}", days[0]); println!("Number of zeros: {}", zeros.len()); } |
Important rule: The size must be a constant expression known at compile time — no runtime variables!
Wrong:
|
0 1 2 3 4 5 6 7 |
let n = 10; let arr = [0; n]; // ERROR — n is not const |
3. Accessing Elements – Index & Safety
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
fn main() { let scores = [85, 92, 78, 95, 88]; println!("First score: {}", scores[0]); println!("Last score: {}", scores[4]); // println!("{}", scores[10]); // panic at runtime! (index out of bounds) // Safe access with .get() match scores.get(10) { Some(value) => println!("Value: {}", value), None => println!("Index 10 is out of bounds"), } } |
- arr[index] → direct access, panics on out-of-bounds (debug & release)
- arr.get(index) → returns Option<&T> → safe & idiomatic
4. Iterating Over Arrays
Rust gives you several nice ways:
|
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() { let cities = ["Hyderabad", "Secunderabad", "Warangal", "Nizamabad"]; // Way 1: by value (moves/copies elements — works for Copy types) for city in cities { println!("City: {}", city); } // Way 2: by reference (most common when elements are not Copy) for city in &cities { println!("City ref: {}", city); } // Way 3: with index (very common!) for (index, city) in cities.iter().enumerate() { println!("Rank {}: {}", index + 1, city); } // Way 4: mutable iteration let mut temps = [28, 30, 32]; for temp in &mut temps { *temp += 2; // increase by 2°C } println!("Warmer temps: {:?}", temps); } |
5. Arrays vs Slices vs Vec – Quick Comparison
| Feature | Array [T; N] | Slice &[T] / &mut [T] | Vec<T> |
|---|---|---|---|
| Size | Fixed at compile time | Dynamic view | Dynamic / growable |
| Memory | Stack | Borrowed (stack/heap/static) | Heap |
| Can grow? | No | No | Yes |
| Type includes size? | Yes — [i32; 5] ≠ [i32; 6] | No — just &[i32] | No — just Vec<i32> |
| Typical use | Small fixed data | Function params, views | Most real-world lists |
| Performance | Fastest (no indirection) | Very fast | Slightly slower (heap) |
6. Passing Arrays to Functions
|
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 |
fn print_weekdays(days: &[&str; 7]) { // array size must match for day in days { println!("Day: {}", day); } } fn print_any_days(days: &[&str]) { // slice — flexible size for day in days { println!("Flexible day: {}", day); } } fn main() { let full_week = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; print_weekdays(&full_week); // OK — size matches // print_weekdays(&full_week[0..5]); // ERROR — wrong size print_any_days(&full_week); // OK — slice print_any_days(&full_week[0..5]); // OK — smaller slice } |
→ In real code you almost always use slices &[T] in function parameters — much more flexible.
7. Common Gotchas & Tips (Teacher Warnings)
- No dynamic size — if size comes from user input or runtime → use Vec
- Copy trait — arrays of Copy types are copied when passed by value
- No negative indexing — arr[-1] does not work
- Bounds panic — always prefer .get() or .get_mut() in unsafe situations
- Stack size limit — very large arrays (e.g. [u8; 10_000_000]) may cause stack overflow → use Vec or Box<[u8]>
Practice Challenge for Today
Create a small project:
|
0 1 2 3 4 5 6 7 |
cargo new rust_arrays cd rust_arrays |
In main.rs try to:
- Create array of 7 days temperatures [f32; 7]
- Compute average using loop (sum / 7.0)
- Find max and min temperature
- Create function that takes &[f32] and prints min/max/avg
- Try passing array of wrong size → see compiler error
Want next?
- Slices in much more depth (they are super important)?
- Vec<T> deep dive with all methods?
- Iterators on arrays/slices (.iter(), .enumerate(), .map())?
- Or custom structs containing arrays?
Just tell me — your Rust teacher is right here with you! 🦀🚀
