Arrays and Slices
Arrays and Slices
Level 1 — Rust Fixed-size contiguous sequences (
[T; N]) and dynamically-sized views into contiguous sequences (&[T]) in Rust.
1. Prerequisites
- Compound Types — Fixed-length sequences built on primitive scalar types.
2. Term Category
Rust Data Structure (the stack/view dichotomy): Fixed-size stack arrays [T; N] and dynamically-sized reference slice views &[T].
3. Explanation
(1) Design Motivation — "Why did we design this?"
Allocating dynamic memory on the heap for small, fixed-length collections (like RGB color channels, fixed 3D coordinates, or buffer chunks) incurs unnecessary memory allocation overhead.
Rust distinguishes between fixed-size stack arrays [T; N] (where capacity is part of the static compile-time type) and slice views &[T] (a borrowed reference view representing a dynamically-sized contiguous sequence of elements). Slice views allow functions to operate generically over arrays, vectors, or sub-regions without copying memory.
(2) Reality Metaphor
A physical photo album vs. a cardboard slide viewer frame: the photo album ([T; N]) has a fixed number of bound plastic sleeve pages; the slide viewer frame (&[T]) is a window placed over any continuous section of photos to inspect them without detaching them from the album.
(3) Rust Code Examples
Short Snippet
let arr: [i32; 3] = [10, 20, 30];
let slice: &[i32] = &arr[1..];
assert_eq!(slice[0], 20);
Fuller Example
pub fn sum_elements(slice: &[i32]) -> i32 {
slice.iter().sum()
}
fn main() {
let stack_array: [i32; 4] = [1, 2, 3, 4];
let heap_vec: Vec<i32> = vec![5, 6, 7, 8];
// Both arrays and vectors coerce to &[i32] slices!
assert_eq!(sum_elements(&stack_array), 10);
assert_eq!(sum_elements(&heap_vec), 26);
assert_eq!(sum_elements(&stack_array[1..3]), 5);
}
4. Common Mistakes & Pitfalls
Mistake 1: Out-of-Bounds Index Panic
The mistake: Accessing an array or slice element using an index equal to or greater than its length arr[arr.len()].
Why it is wrong: Rust performs bounds checking on direct subscript indexing arr[i]. If the index is out of bounds, Rust panics at runtime to prevent buffer overflow vulnerabilities.
Incorrect:
let arr = [10, 20]; let val = arr[2]; // Runtime Panic!
Fix:
let val = arr.get(2).copied().unwrap_or(0); // Safe fallible access via .get()
Mistake 2: Attempting to Mutate Elements Through an Immutable Slice &[T]
The mistake: Trying to assign a new value slice[0] = 42 through a shared &[T] slice reference.
Why it is wrong: Shared references &[T] are strictly immutable to prevent data races. Mutable element mutation requires &mut [T].
Incorrect:
fn update(s: &[i32]) { s[0] = 1; } // Compiler Error!
Fix:
fn update(s: &mut [i32]) { s[0] = 1; } // Use &mut [T] slice!
Mistake 3: Mismatching Array Length Types in Functions
The mistake: Defining a function accepting [i32; 4] and attempting to pass [i32; 5].
Why it is wrong: Array capacity is part of the static type. [i32; 4] and [i32; 5] are completely different types.
Incorrect:
fn process(a: [i32; 4]) {} process([1, 2, 3, 4, 5]); // Type Mismatch!
Fix:
fn process(s: &[i32]) {} process(&[1, 2, 3, 4, 5]); // Accept &[T] slice!
5. Practice Exercises
Exercise 1: High-Performance Sliding Window Average Signal Processor
Scenario: Build a digital signal processing function sliding_window_avg(samples: &[f64], window_size: usize) -> Vec<f64> accepting a slice of input audio samples and returning calculated window averages.
Requirements:
- Accept
&[f64]slice parameter. - Use slice windows
samples.windows(window_size). - Return
Vec<f64>. - Write unit tests.
Answer
Implementation
pub fn sliding_window_avg(samples: &[f64], window_size: usize) -> Vec<f64> {
if window_size == 0 || samples.len() < window_size {
return Vec::new();
}
samples
.windows(window_size)
.map(|w| w.iter().sum::<f64>() / (window_size as f64))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sliding_window() {
let array_data: [f64; 5] = [1.0, 2.0, 3.0, 4.0, 5.0];
let averages = sliding_window_avg(&array_data, 3);
assert_eq!(averages, vec![2.0, 3.0, 4.0]);
}
}
Technical Explanation
- Function parameter
samples: &[f64]allows accepting stack arrays[f64; N], sub-slices, or heapVec<f64>zero-copy. - Uses
.windows(N)iterator over slice sub-views.
Exercise 2: In-Place Buffer Sanitizer with Mutable Slices &mut [T]
Scenario: Build a network buffer sanitizer clamp_buffer(buf: &mut [u8], max_val: u8) replacing byte values exceeding max_val.
Requirements:
- Accept
&mut [u8]slice. - Modify elements in-place.
- Write unit tests.
Answer
Implementation
pub fn clamp_buffer(buf: &mut [u8], max_val: u8) {
for byte in buf.iter_mut() {
if *byte > max_val {
*byte = max_val;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_clamp_buffer() {
let mut stack_buf: [u8; 4] = [50, 150, 200, 10];
clamp_buffer(&mut stack_buf, 100);
assert_eq!(stack_buf, [50, 100, 100, 10]);
}
}
Technical Explanation
- Operates directly on caller's stack array in-place without dynamic heap allocations.
Exercise 3: Fixed RGB Pixel Color Channel Converter
Scenario: Implement a fixed-size 3-byte RGB array converter rgb_to_grayscale(rgb: [u8; 3]) -> u8.
Requirements:
- Accept
[u8; 3]fixed stack array. - Calculate weighted luminance.
- Write unit tests.
Answer
Implementation
pub fn rgb_to_grayscale(rgb: [u8; 3]) -> u8 {
let r = rgb[0] as f32;
let g = rgb[1] as f32;
let b = rgb[2] as f32;
(0.299 * r + 0.587 * g + 0.114 * b) as u8
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rgb_conversion() {
let pixel: [u8; 3] = [255, 255, 255];
assert_eq!(rgb_to_grayscale(pixel), 255);
}
}
Technical Explanation
[u8; 3]enforces exact 3-element stack allocation for fixed graphics pixel data.
6. Related Terms
- SIMD (
std::simd) — Vec<T>— The heap-allocated dynamic array version.- Compound Types — Related concept: Compound Types.
IndexandIndexMutTraits — Related concept:IndexandIndexMutTraits.
7. Key Takeaways
- Arrays
[T; N]have a fixed length known at compile time. - Slices
&[T]are borrowed views over contiguous memory. - Prefer
&[T]or&mut [T]slice parameters in public functions for API flexibility. - Use
.get(idx)for safe out-of-bounds bounds checking.