Arrays
An array in Rust is a fixed-size collection of elements of the same type, stored contiguously in memory.
Rust arrays are simple, fast, and safe, but not growable.
let arr = [1, 2, 3, 4, 5];
- All elements must be the same type
- Length is known at compile time
- Stored on the stack (by default)
Type of an Array
let arr: [i32; 5] = [1, 2, 3, 4, 5];
Syntax:
[element_type; number_of_elements]
Key Characteristics of Arrays
| Feature | Arrays |
|---|---|
| Size | Fixed |
| Memory | Contiguous |
| Grow/Shrink | ❌ No |
| Indexing | O(1) |
| Safety | Bounds-checked |
| Mutability | Optional |
Creating Arrays
- Standard Initialization:
let numbers = [10, 20, 30, 40]; - Initialize with Same Value:
let zeros = [0; 5];Creates:[0, 0, 0, 0, 0] - Mutable Array:
let mut scores = [50, 60, 70];scores[1] = 85;
Accessing Array Elements
Using Index
let arr = [1, 2, 3];
println!("{}", arr[0]); // 1
Out-of-Bounds Access (Runtime Panic)
let arr = [1, 2, 3];
let x = arr[10]; // ❌ panic
Rust performs runtime bounds checking to ensure safety.
Safe Access Using .get()
let arr = [1, 2, 3];
match arr.get(10) {
Some(value) => println!("{}", value),
None => println!("Index out of bounds"),
}
Iterating Over Arrays
Using for Loop (Recommended)
let arr = [10, 20, 30];
for value in arr {
println!("{}", value);
}
📌 This works because arrays implement Copy for small types.
Using Index-Based Loop
let arr = [10, 20, 30];
for i in 0..arr.len() {
println!("Index {} = {}", i, arr[i]);
}
Using Iterator Methods
let arr = [1, 2, 3, 4];
for value in arr.iter() {
println!("{}", value);
}
Array Slices (&[T])
A slice is a reference to part (or all) of an array.
let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..4];
slice type: &[i32]
Slice Properties
| Feature | Slice |
|---|---|
| Ownership | ❌ No |
| Size | Dynamic |
| Mutability | Depends |
| Memory | Borrowed |
Mutable Slice
let mut arr = [1, 2, 3, 4];
let slice = &mut arr[1..3];
slice[0] = 20;
Array becomes: [1, 20, 3, 4]
Arrays vs Vectors (Very Important)
| Feature | Array | Vector (Vec<T>) |
|---|---|---|
| Size | Fixed | Dynamic |
| Memory | Stack | Heap |
| Resize | ❌ | ✅ |
| Use case | Known-size data | Flexible collections |
Use arrays when:
- Size is fixed
- Performance is critical
- Data is small
Use vectors when:
- Size may change
- Input comes from users/files
Passing Arrays to Functions
Passing by Reference (Best Practice)
fn print_array(arr: &[i32]) {
for x in arr {
println!("{}", x);
}
}
Usage:
let numbers = [1, 2, 3];
print_array(&numbers);
&[i32] works for: Arrays, Slices, Vectors
Passing Fixed-Size Array
fn sum(arr: [i32; 3]) -> i32 {
arr.iter().sum()
}
Less flexible (size must match exactly).
Multidimensional Arrays
2D Array Example
let matrix = [
[1, 2, 3],
[4, 5, 6],
];
Access Elements: println!("{}", matrix[1][2]); // 6
Iterating 2D Arrays
for row in matrix {
for val in row {
print!("{} ", val);
}
println!();
}
Memory Safety Highlights
- Fixed size prevents unexpected reallocations
- Bounds checking prevents buffer overflows
- Ownership rules prevent data races
Rust arrays are low-level but safe.