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