Complete Guide to Rust Arrays

Introduction to Rust Arrays

Arrays in Rust are fixed-size collections of elements of the same type. They are stack-allocated and provide fast, contiguous memory access. Unlike vectors, arrays have a fixed length known at compile time, making them ideal for scenarios where you know the exact number of elements you need.

Key Concepts

  • Fixed Size: Length is part of the type and known at compile time
  • Stack Allocated: Stored on the stack, not heap
  • Homogeneous: All elements must be the same type
  • Zero-Cost: No runtime overhead compared to C arrays
  • Type Safety: Bounds checking at runtime (in debug builds)

1. Array Basics

Declaration and Initialization

fn main() { // Explicit type annotation let arr1: [i32; 5] = [1, 2, 3, 4, 5]; // Type inference let arr2 = [1, 2, 3, 4, 5]; // Array with default values let zeros = [0; 10]; // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] let threes = [3; 5]; // [3, 3, 3, 3, 3] // Mutable array let mut mutable_arr = [1, 2, 3, 4, 5]; mutable_arr[0] = 10; println!("arr1: {:?}", arr1); println!("zeros: {:?}", zeros); println!("mutable_arr: {:?}", mutable_arr); // Array with different initialization patterns let squares = [1, 4, 9, 16, 25]; let evens = [2, 4, 6, 8, 10]; }

Array Type Signature

fn main() { // Array type is [T; N] where T is element type and N is length let arr: [i32; 5] = [1, 2, 3, 4, 5]; // Different sizes are different types let arr3: [i32; 3] = [1, 2, 3]; let arr5: [i32; 5] = [1, 2, 3, 4, 5]; // arr3 = arr5; // Error: mismatched types // Size is part of the type println!("Size of [i32; 5]: {} bytes", std::mem::size_of::<[i32; 5]>()); println!("Size of [i32; 10]: {} bytes", std::mem::size_of::<[i32; 10]>()); // Arrays implement common traits fn print_array<T: std::fmt::Debug>(arr: &[T]) { println!("{:?}", arr); } print_array(&arr); }

2. Accessing Array Elements

Indexing

fn main() { let arr = [10, 20, 30, 40, 50]; // Direct indexing let first = arr[0]; let third = arr[2]; let last = arr[4]; println!("First: {}, Third: {}, Last: {}", first, third, last); // Bounds checking (panics in debug, wraps in release) // let out_of_bounds = arr[10]; // This would panic // Safe access with get() match arr.get(2) { Some(value) => println!("Element at index 2: {}", value), None => println!("Index out of bounds"), } match arr.get(10) { Some(value) => println!("Element at index 10: {}", value), None => println!("Index 10 out of bounds"), // This prints } // Get with default let value = arr.get(2).unwrap_or(&-1); println!("Value: {}", value); // First and last elements if let Some(first) = arr.first() { println!("First: {}", first); } if let Some(last) = arr.last() { println!("Last: {}", last); } }

Slicing Arrays

fn main() { let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Full slice let full_slice = &arr[..]; println!("Full slice: {:?}", full_slice); // Partial slices let slice1 = &arr[2..5]; // [3, 4, 5] let slice2 = &arr[..4]; // [1, 2, 3, 4] let slice3 = &arr[6..]; // [7, 8, 9, 10] let slice4 = &arr[2..=5]; // [3, 4, 5, 6] (inclusive) println!("slice1: {:?}", slice1); println!("slice2: {:?}", slice2); println!("slice3: {:?}", slice3); println!("slice4: {:?}", slice4); // Mutable slices let mut mut_arr = [1, 2, 3, 4, 5]; let mut_slice = &mut mut_arr[1..4]; mut_slice[0] = 20; mut_slice[1] = 30; mut_slice[2] = 40; println!("Modified array: {:?}", mut_arr); // [1, 20, 30, 40, 5] // Slice from mutable array let slice = &mut mut_arr[..]; slice[0] = 100; println!("All modified: {:?}", mut_arr); // [100, 20, 30, 40, 5] }

3. Array Iteration

Basic Iteration

fn main() { let arr = [10, 20, 30, 40, 50]; // For loop over references (doesn't consume) for element in &arr { println!("Element: {}", element); } // For loop over values (consumes if not Copy) for element in arr { println!("Element: {}", element); } // println!("{:?}", arr); // Still works because i32 is Copy // Iterate with index for i in 0..arr.len() { println!("arr[{}] = {}", i, arr[i]); } // Using iter() method for element in arr.iter() { println!("iter(): {}", element); } // Mutable iteration let mut mut_arr = [1, 2, 3, 4, 5]; for element in mut_arr.iter_mut() { *element *= 2; } println!("After doubling: {:?}", mut_arr); }

Advanced Iteration Techniques

fn main() { let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Enumerate - get index and value for (i, value) in arr.iter().enumerate() { println!("arr[{}] = {}", i, value); } // Filter let evens: Vec<_> = arr.iter() .filter(|&&x| x % 2 == 0) .collect(); println!("Evens: {:?}", evens); // Map let doubled: Vec<_> = arr.iter() .map(|&x| x * 2) .collect(); println!("Doubled: {:?}", doubled); // Fold (reduce) let sum = arr.iter().fold(0, |acc, &x| acc + x); println!("Sum: {}", sum); // Any and All let has_negative = arr.iter().any(|&x| x < 0); let all_positive = arr.iter().all(|&x| x > 0); println!("Has negative: {}, All positive: {}", has_negative, all_positive); // Find if let Some(value) = arr.iter().find(|&&x| x == 5) { println!("Found: {}", value); } // Position if let Some(pos) = arr.iter().position(|&x| x == 7) { println!("7 found at index: {}", pos); } }

4. Array Methods and Operations

Basic Methods

fn main() { let arr = [1, 2, 3, 4, 5]; // Length println!("Length: {}", arr.len()); // Is empty println!("Is empty: {}", arr.is_empty()); // Check if contains println!("Contains 3: {}", arr.contains(&3)); println!("Contains 10: {}", arr.contains(&10)); // First and last println!("First: {:?}", arr.first()); println!("Last: {:?}", arr.last()); // Get specific element println!("Element at 2: {:?}", arr.get(2)); println!("Element at 10: {:?}", arr.get(10)); // Split array let (left, right) = arr.split_at(3); println!("Left: {:?}, Right: {:?}", left, right); // Windows for window in arr.windows(3) { println!("Window: {:?}", window); } // Chunks for chunk in arr.chunks(2) { println!("Chunk: {:?}", chunk); } // Chunks with remainder for chunk in arr.chunks(3) { println!("Chunk of 3: {:?}", chunk); } }

Searching and Sorting

fn main() { let mut arr = [5, 2, 8, 1, 9, 3, 7, 4, 6]; // Sort arr.sort(); println!("Sorted: {:?}", arr); // Sort in reverse arr.sort_by(|a, b| b.cmp(a)); println!("Reverse sorted: {:?}", arr); // Binary search (requires sorted array) arr.sort(); match arr.binary_search(&5) { Ok(index) => println!("Found 5 at index {}", index), Err(index) => println!("5 not found, could be inserted at {}", index), } // Search with custom comparator let mut pairs = [(1, "one"), (3, "three"), (2, "two")]; pairs.sort_by(|a, b| a.0.cmp(&b.0)); println!("Sorted pairs: {:?}", pairs); // Check if sorted println!("Is sorted: {}", arr.is_sorted()); // Dedup (remove consecutive duplicates) let mut dup_arr = [1, 1, 2, 2, 3, 3, 4]; dup_arr.sort(); dup_arr.dedup(); println!("After dedup: {:?}", dup_arr); }

Array Transformations

fn main() { let arr = [1, 2, 3, 4, 5]; // Reverse let reversed: Vec<_> = arr.iter().rev().collect(); println!("Reversed: {:?}", reversed); // Rotate left let rotate_left = [&arr[1..], &arr[..1]].concat(); println!("Rotate left: {:?}", rotate_left); // Rotate right let rotate_right = [&arr[arr.len()-1..], &arr[..arr.len()-1]].concat(); println!("Rotate right: {:?}", rotate_right); // Fill with value let mut fill_arr = [0; 5]; fill_arr.fill(42); println!("Filled: {:?}", fill_arr); // Fill with range for (i, val) in fill_arr.iter_mut().enumerate() { *val = i * 10; } println!("Range fill: {:?}", fill_arr); // Map to new array (using const generics) fn map_array<T, U, const N: usize>(arr: [T; N], mut f: impl FnMut(T) -> U) -> [U; N] { let mut result: [std::mem::MaybeUninit<U>; N] = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; for (i, x) in arr.into_iter().enumerate() { result[i].write(f(x)); } unsafe { std::mem::transmute_copy(&result) } } let doubled = map_array(arr, |x| x * 2); println!("Doubled array: {:?}", doubled); }

5. Multidimensional Arrays

2D Arrays

fn main() { // 2D array declaration let matrix: [[i32; 3]; 3] = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; // Access elements println!("matrix[1][1] = {}", matrix[1][1]); // 5 // Iterate over 2D array for row in &matrix { for element in row { print!("{} ", element); } println!(); } // Mutable 2D array let mut mut_matrix = [[0; 3]; 3]; for i in 0..3 { for j in 0..3 { mut_matrix[i][j] = (i * 3 + j + 1) as i32; } } println!("Mut matrix: {:?}", mut_matrix); // Jagged arrays (using Vec for different lengths) let jagged: [Vec<i32>; 3] = [ vec![1, 2], vec![3, 4, 5], vec![6, 7, 8, 9], ]; for (i, row) in jagged.iter().enumerate() { println!("Row {}: {:?}", i, row); } }

3D Arrays

fn main() { // 3D array let cube: [[[i32; 2]; 2]; 2] = [ [[1, 2], [3, 4]], [[5, 6], [7, 8]], ]; println!("cube[0][0][0] = {}", cube[0][0][0]); // 1 println!("cube[1][1][1] = {}", cube[1][1][1]); // 8 // Iterate through 3D for (i, layer) in cube.iter().enumerate() { println!("Layer {}:", i); for (j, row) in layer.iter().enumerate() { print!(" Row {}: ", j); for (k, &val) in row.iter().enumerate() { print!("{} ", val); } println!(); } } // Create 3D array dynamically let mut dynamic_cube = [[[0; 3]; 3]; 3]; for i in 0..3 { for j in 0..3 { for k in 0..3 { dynamic_cube[i][j][k] = (i * 9 + j * 3 + k) as i32; } } } println!("Dynamic cube: {:?}", dynamic_cube); }

Matrix Operations

fn main() { // Matrix addition let a = [[1, 2], [3, 4]]; let b = [[5, 6], [7, 8]]; let mut c = [[0; 2]; 2]; for i in 0..2 { for j in 0..2 { c[i][j] = a[i][j] + b[i][j]; } } println!("Matrix A + B = {:?}", c); // Matrix multiplication let a = [[1, 2], [3, 4]]; let b = [[5, 6], [7, 8]]; let mut d = [[0; 2]; 2]; for i in 0..2 { for j in 0..2 { for k in 0..2 { d[i][j] += a[i][k] * b[k][j]; } } } println!("Matrix A * B = {:?}", d); // Transpose let mut transpose = [[0; 2]; 2]; for i in 0..2 { for j in 0..2 { transpose[j][i] = a[i][j]; } } println!("Transpose of A = {:?}", transpose); }

6. Arrays and Functions

Passing Arrays to Functions

// Pass by value (copy for Copy types, move otherwise) fn process_array(mut arr: [i32; 5]) -> [i32; 5] { for i in 0..arr.len() { arr[i] *= 2; } arr } // Pass by reference (immutable) fn print_array(arr: &[i32; 5]) { println!("Array: {:?}", arr); } // Pass by mutable reference fn modify_array(arr: &mut [i32; 5]) { for i in 0..arr.len() { arr[i] += 10; } } // Pass slice (most flexible for functions) fn sum_slice(arr: &[i32]) -> i32 { arr.iter().sum() } // Generic array function fn print_any_array<T: std::fmt::Debug, const N: usize>(arr: &[T; N]) { println!("Array of length {}: {:?}", N, arr); } fn main() { let arr = [1, 2, 3, 4, 5]; // Pass by reference print_array(&arr); // Pass by value (returns modified copy) let doubled = process_array(arr); println!("Original: {:?}, Doubled: {:?}", arr, doubled); // Pass by mutable reference let mut mut_arr = [1, 2, 3, 4, 5]; modify_array(&mut mut_arr); println!("Modified: {:?}", mut_arr); // Pass as slice let sum = sum_slice(&arr); println!("Sum: {}", sum); // Generic function print_any_array(&arr); print_any_array(&['a', 'b', 'c']); }

Returning Arrays from Functions

// Return fixed-size array fn create_array() -> [i32; 5] { [1, 2, 3, 4, 5] } // Return array from computation fn generate_squares(n: usize) -> [i32; 5] { let mut arr = [0; 5]; for i in 0..5 { arr[i] = ((i + 1) * (i + 1)) as i32; } arr } // Using const generics to return arrays of any size fn fill_array<const N: usize>(value: i32) -> [i32; N] {

[value; N]

} // Return array from Option fn maybe_array(flag: bool) -> Option<[i32; 3]> { if flag { Some([1, 2, 3]) } else { None } } fn main() { let arr1 = create_array(); println!("Created: {:?}", arr1); let squares = generate_squares(5); println!("Squares: {:?}", squares); let tens: [i32; 10] = fill_array(10); println!("Tens: {:?}", tens); match maybe_array(true) { Some(arr) => println!("Got array: {:?}", arr), None => println!("No array"), } }

7. Arrays and Generics

Const Generics

// Function that works with arrays of any size fn sum_array<T: std::ops::Add<Output = T> + Default + Copy, const N: usize>(arr: [T; N]) -> T { let mut sum = T::default(); for i in 0..N { sum = sum + arr[i]; } sum } // Generic array struct struct ArrayWrapper<T, const N: usize> { data: [T; N], } impl<T: std::fmt::Debug, const N: usize> ArrayWrapper<T, N> { fn new(data: [T; N]) -> Self { ArrayWrapper { data } } fn get(&self, index: usize) -> Option<&T> { self.data.get(index) } fn len(&self) -> usize { N } } // Const generic with bounds fn compare_arrays<T: PartialEq, const N: usize>(a: &[T; N], b: &[T; N]) -> bool { a == b } fn main() { let arr1 = [1, 2, 3, 4, 5]; let arr2 = [1, 2, 3, 4, 5]; let arr3 = [1, 2, 3, 4, 6]; println!("Sum of arr1: {}", sum_array(arr1)); let sum_float = sum_array([1.1, 2.2, 3.3]); println!("Sum of floats: {}", sum_float); let wrapper = ArrayWrapper::new([10, 20, 30, 40]); println!("Wrapper length: {}", wrapper.len()); println!("Element at 2: {:?}", wrapper.get(2)); println!("arr1 == arr2: {}", compare_arrays(&arr1, &arr2)); println!("arr1 == arr3: {}", compare_arrays(&arr1, &arr3)); }

Arrays in Traits

trait ArrayOperations<T, const N: usize> { fn sum(&self) -> T; fn product(&self) -> T; fn average(&self) -> f64; } impl<T, const N: usize> ArrayOperations<T, N> for [T; N] where T: std::ops::Add<Output = T> + std::ops::Mul<Output = T> + Default + Copy, f64: From<T>, { fn sum(&self) -> T { let mut sum = T::default(); for i in 0..N { sum = sum + self[i]; } sum } fn product(&self) -> T { let mut product = self[0]; for i in 1..N { product = product * self[i]; } product } fn average(&self) -> f64 { let sum: f64 = self.sum().into(); sum / (N as f64) } } fn main() { let numbers = [1, 2, 3, 4, 5]; println!("Sum: {}", numbers.sum()); println!("Product: {}", numbers.product()); println!("Average: {}", numbers.average()); let floats = [1.5, 2.5, 3.5, 4.5]; println!("Float sum: {}", floats.sum()); println!("Float average: {}", floats.average()); }

8. Array Performance

Stack vs Heap

fn main() { // Stack allocation (fast) let stack_array = [0; 1000]; // Heap allocation via Box (still need to copy) let heap_array = Box::new([0; 1000]); // Vector (heap allocated, dynamic) let vec = vec![0; 1000]; println!("Stack array size: {} bytes", std::mem::size_of_val(&stack_array)); println!("Boxed array size: {} bytes", std::mem::size_of_val(&heap_array)); println!("Vector size: {} bytes", std::mem::size_of_val(&vec)); // Performance comparison use std::time::Instant; // Stack array access let start = Instant::now(); let mut sum_stack = 0; for i in 0..1000 { sum_stack += stack_array[i]; } println!("Stack access time: {:?}", start.elapsed()); // Heap array access let start = Instant::now(); let mut sum_heap = 0; for i in 0..1000 { sum_heap += heap_array[i]; } println!("Heap access time: {:?}", start.elapsed()); }

Cache Efficiency

fn main() { // Cache-friendly sequential access let arr = [0; 10000]; let start = std::time::Instant::now(); for i in 0..10000 { let _ = arr[i]; } println!("Sequential access: {:?}", start.elapsed()); // Cache-unfriendly random access (simulated) let start = std::time::Instant::now(); for i in 0..10000 { let idx = (i * 997) % 10000; // Non-sequential pattern let _ = arr[idx]; } println!("Random access: {:?}", start.elapsed()); // Row-major vs column-major for 2D let matrix = [[0; 1000]; 1000]; // Row-major access (cache-friendly) let start = std::time::Instant::now(); for i in 0..1000 { for j in 0..1000 { let _ = matrix[i][j]; } } println!("Row-major: {:?}", start.elapsed()); // Column-major access (cache-unfriendly) let start = std::time::Instant::now(); for j in 0..1000 { for i in 0..1000 { let _ = matrix[i][j]; } } println!("Column-major: {:?}", start.elapsed()); }

9. Common Array Patterns

Sliding Window

fn main() { let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Simple sliding window for window in arr.windows(3) { println!("Window: {:?}", window); } // Moving average let moving_avg: Vec<f64> = arr.windows(3) .map(|w| w.iter().sum::<i32>() as f64 / 3.0) .collect(); println!("Moving average: {:?}", moving_avg); // Max in each window let max_in_window: Vec<_> = arr.windows(4) .map(|w| w.iter().max().unwrap()) .collect(); println!("Max in window: {:?}", max_in_window); // Overlapping windows with stride for chunk in arr.chunks(3) { println!("Chunk: {:?}", chunk); } // Custom sliding window with step let step = 2; for i in (0..arr.len()).step_by(step) { if i + 3 <= arr.len() { println!("Window at {}: {:?}", i, &arr[i..i+3]); } } }

Two-Pointer Technique

fn main() { // Find pair that sums to target let mut arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; arr.sort(); let target = 10; let mut left = 0; let mut right = arr.len() - 1; while left < right { let sum = arr[left] + arr[right]; if sum == target { println!("Found pair: {} + {} = {}", arr[left], arr[right], target); left += 1; right -= 1; } else if sum < target { left += 1; } else { right -= 1; } } // Reverse array in place let mut arr = [1, 2, 3, 4, 5]; let mut left = 0; let mut right = arr.len() - 1; while left < right { arr.swap(left, right); left += 1; right -= 1; } println!("Reversed: {:?}", arr); // Remove duplicates from sorted array let mut sorted = [1, 1, 2, 2, 3, 3, 4, 4, 5]; let mut write_pos = 1; for read_pos in 1..sorted.len() { if sorted[read_pos] != sorted[write_pos - 1] { sorted[write_pos] = sorted[read_pos]; write_pos += 1; } } println!("After removing duplicates: {:?}", &sorted[..write_pos]); }

Binary Search

fn main() { let arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; // Binary search implementation fn binary_search<T: Ord>(arr: &[T], target: &T) -> Option<usize> { let mut left = 0; let mut right = arr.len(); while left < right { let mid = left + (right - left) / 2; match arr[mid].cmp(target) { std::cmp::Ordering::Equal => return Some(mid), std::cmp::Ordering::Less => left = mid + 1, std::cmp::Ordering::Greater => right = mid, } } None } for &target in &[5, 10, 15] { match binary_search(&arr, &target) { Some(pos) => println!("Found {} at index {}", target, pos), None => println!("{} not found", target), } } // Find first element greater than target let target = 8; let result = arr.iter().position(|&x| x > target); println!("First element > {} is at index {:?}", target, result); // Find range of equal elements let duplicates = [1, 2, 2, 2, 3, 4, 4, 5]; let target = 2; let start = duplicates.iter().position(|&x| x == target); let end = duplicates.iter().rposition(|&x| x == target); match (start, end) { (Some(s), Some(e)) => println!("Range of {}: [{}, {}]", target, s, e), _ => println!("{} not found", target), } }

10. Arrays and Pattern Matching

Destructuring Arrays

fn main() { // Basic destructuring let arr = [1, 2, 3, 4, 5]; let [a, b, c, d, e] = arr; println!("a: {}, b: {}, c: {}, d: {}, e: {}", a, b, c, d, e); // Ignoring elements with .. let [first, second, ..] = arr; println!("First: {}, Second: {}", first, second); let [.., last] = arr; println!("Last: {}", last); let [first, .., last] = arr; println!("First: {}, Last: {}", first, last); let [first, second, middle @ .., fourth, fifth] = arr; println!("First: {}, Second: {}, Middle: {:?}, Fourth: {}, Fifth: {}", first, second, middle, fourth, fifth); // Destructuring in match match arr { [1, 2, ..] => println!("Starts with 1,2"), [x, y, z, ..] if x < y && y < z => println!("Increasing start"), [a, b, c, d, e] if a + e == b + d => println!("Symmetrical"), _ => println!("Other pattern"), } }

Pattern Matching with Arrays

fn main() { // Match on array length and content fn analyze_array(arr: &[i32]) { match arr { [] => println!("Empty array"), [x] => println!("Single element: {}", x), [x, y] => println!("Two elements: {}, {}", x, y), [x, y, z] => println!("Three elements: {}, {}, {}", x, y, z), [x, .., y] => println!("First: {}, Last: {}, and {} in between", x, y, arr.len() - 2), _ => println!("Array with {} elements", arr.len()), } } analyze_array(&[]); analyze_array(&[1]); analyze_array(&[1, 2]); analyze_array(&[1, 2, 3]); analyze_array(&[1, 2, 3, 4, 5]); // Pattern matching with guards let arr = [1, 3, 5, 7, 9]; match arr { [x, y, ..] if x < y => println!("Increasing start"), [x, y, ..] if x > y => println!("Decreasing start"), _ => println!("Other pattern"), } // Extract based on pattern let arr = [Some(1), Some(2), Some(3), None, Some(5)]; if let [Some(x), Some(y), ..] = arr { println!("First two are Some: {}, {}", x, y); } }

11. Arrays and Serialization

JSON Serialization

use serde::{Serialize, Deserialize}; use serde_json; #[derive(Debug, Serialize, Deserialize)] struct Data { name: String, values: [i32; 5], matrix: [[i32; 2]; 2], } fn main() -> Result<(), Box<dyn std::error::Error>> { let data = Data { name: "Test".to_string(), values: [1, 2, 3, 4, 5], matrix: [[1, 2], [3, 4]], }; // Serialize to JSON let json = serde_json::to_string_pretty(&data)?; println!("Serialized: {}", json); // Deserialize from JSON let deserialized: Data = serde_json::from_str(&json)?; println!("Deserialized: {:?}", deserialized); // Working with raw JSON arrays let json_array = "[1, 2, 3, 4, 5]"; let array: [i32; 5] = serde_json::from_str(json_array)?; println!("Array from JSON: {:?}", array); // 2D array from JSON let json_matrix = "[[1,2],[3,4]]"; let matrix: [[i32; 2]; 2] = serde_json::from_str(json_matrix)?; println!("Matrix from JSON: {:?}", matrix); Ok(()) }

Binary Serialization

use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt}; use std::io::Cursor; fn main() -> Result<(), Box<dyn std::error::Error>> { let arr = [1, 2, 3, 4, 5]; // Write array to bytes let mut bytes = Vec::new(); for &num in &arr { bytes.write_i32::<LittleEndian>(num)?; } println!("Binary representation: {:?}", bytes); // Read array from bytes let mut cursor = Cursor::new(bytes); let mut read_arr = [0; 5]; for i in 0..5 { read_arr[i] = cursor.read_i32::<LittleEndian>()?; } println!("Read back: {:?}", read_arr); // Using bytemuck for zero-copy use bytemuck::{Pod, Zeroable, cast_slice, from_bytes}; #[repr(C)] #[derive(Debug, Copy, Clone, Zeroable, Pod)] struct Color { r: u8, g: u8, b: u8, } let colors = [ Color { r: 255, g: 0, b: 0 }, Color { r: 0, g: 255, b: 0 }, Color { r: 0, g: 0, b: 255 }, ]; // Cast to byte slice let bytes = cast_slice::<Color, u8>(&colors); println!("Colors as bytes: {:?}", bytes); // Cast back let colors2: &[Color; 3] = from_bytes(&bytes[..std::mem::size_of::<[Color; 3]>()]); println!("Colors back: {:?}", colors2); Ok(()) }

12. Advanced Array Techniques

Zero-Copy Views

use std::mem; #[repr(C)] #[derive(Debug, Copy, Clone)] struct Pixel { r: u8, g: u8, b: u8, a: u8, } fn main() { // Raw bytes let raw_data: [u8; 16] = [ 255, 0, 0, 255, // Red pixel 0, 255, 0, 255, // Green pixel 0, 0, 255, 255, // Blue pixel 255, 255, 255, 255, // White pixel ]; // Zero-cast to Pixel array let pixels: &[Pixel; 4] = unsafe { &*(&raw_data as *const _ as *const [Pixel; 4]) }; println!("Pixels: {:?}", pixels); // Work with pixels directly for (i, pixel) in pixels.iter().enumerate() { println!("Pixel {}: RGB({}, {}, {})", i, pixel.r, pixel.g, pixel.b); } // Convert back let back_to_bytes: &[u8; 16] = unsafe { &*(pixels as *const _ as *const [u8; 16]) }; println!("Back to bytes: {:?}", back_to_bytes); }

SIMD Operations

// Requires nightly Rust and feature flags #![cfg_attr(feature = "nightly", feature(portable_simd))] #[cfg(feature = "nightly")] use std::simd::{f32x4, SimdFloat}; #[cfg(feature = "nightly")] fn simd_example() { let a = [1.0, 2.0, 3.0, 4.0]; let b = [5.0, 6.0, 7.0, 8.0]; // Load into SIMD vectors let a_vec = f32x4::from_array(a); let b_vec = f32x4::from_array(b); // SIMD operations let sum = a_vec + b_vec; let product = a_vec * b_vec; println!("SIMD sum: {:?}", sum.to_array()); println!("SIMD product: {:?}", product.to_array()); // Dot product let dot = (a_vec * b_vec).reduce_sum(); println!("Dot product: {}", dot); } #[cfg(not(feature = "nightly"))] fn simd_example() { println!("SIMD requires nightly Rust"); } fn main() { simd_example(); }

Array Pools and Reuse

struct ArrayPool<T, const N: usize> { pools: Vec<[T; N]>, } impl<T: Default + Copy, const N: usize> ArrayPool<T, N> { fn new() -> Self { ArrayPool { pools: Vec::new() } } fn acquire(&mut self) -> [T; N] { self.pools.pop().unwrap_or([T::default(); N]) } fn release(&mut self, mut arr: [T; N]) { // Reset before returning to pool for elem in &mut arr { *elem = T::default(); } self.pools.push(arr); } } fn main() { let mut pool = ArrayPool::<i32, 1024>::new(); // Get arrays from pool let mut arr1 = pool.acquire(); let mut arr2 = pool.acquire(); // Use them arr1[0] = 42; arr2[511] = 100; println!("arr1[0]: {}, arr2[511]: {}", arr1[0], arr2[511]); // Return to pool pool.release(arr1); pool.release(arr2); println!("Pool size: {}", pool.pools.len()); // Reuse let arr3 = pool.acquire(); println!("arr3[0] after reuse: {}", arr3[0]); // 0 (reset) }

Conclusion

Rust arrays provide a powerful, efficient way to work with fixed-size collections:

Key Takeaways

  1. Fixed Size: Length is part of the type system
  2. Stack Allocation: Fast access, no heap overhead
  3. Type Safety: Bounds checking prevents buffer overflows
  4. Pattern Matching: Destructuring and matching support
  5. Const Generics: Generic code for arrays of any size
  6. Zero-Cost: Compiles to efficient machine code

Array vs Vector Comparison

FeatureArrayVector
SizeFixed at compile timeDynamic
AllocationStackHeap
Type[T; N]Vec<T>
ResizableNoYes
PerformanceFaster accessSlightly slower
Use caseKnown sizeUnknown/Changing size

Best Practices

  1. Use arrays when you know the size at compile time
  2. Prefer slices for function parameters
  3. Use const generics for generic array code
  4. Be careful with bounds - use get() for safe access
  5. Consider cache efficiency for large arrays
  6. Profile before optimizing array access patterns

Common Operations Cheat Sheet

// Creation let arr = [1, 2, 3, 4, 5]; let zeros = [0; 100]; let mut mut_arr = [1, 2, 3]; // Access let first = arr[0]; let safe = arr.get(2); let slice = &arr[1..4]; // Information let len = arr.len(); let is_empty = arr.is_empty(); // Iteration for item in &arr { } for item in arr.iter() { } for item in arr.iter_mut() { } for (i, item) in arr.iter().enumerate() { } // Search let contains = arr.contains(&3); let position = arr.iter().position(|&x| x == 3); // Transformation let doubled: Vec<_> = arr.iter().map(|&x| x * 2).collect(); let sum: i32 = arr.iter().sum(); // Modification let mut arr = [1, 2, 3]; arr[0] = 10; arr.swap(1, 2); arr.reverse(); arr.sort();

Rust arrays combine the performance of C arrays with the safety of Rust's type system, making them ideal for systems programming, embedded development, and any scenario where fixed-size collections are needed.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper