Rust: Rust Arrays and Tuples
Last updated: 2026-08-26
Arrays and tuples are the most basic "fixed-size collections" in Rust—arrays store multiple values of the same type, while tuples can store multiple values of different types. They are both allocated on the stack and incur no runtime overhead.
In system programming, fixed-size collections mean a well-defined memory layout and predictable performance. The Rust compiler needs to know how much memory each variable occupies, and the sizes of arrays and tuples are fully determined at compile time.
1. What You'll Learn
- Syntax for Defining and Initializing Arrays
[T; N] - Accessing Array Elements by Index and Out-of-Bounds Checks
- Creating Tuples and Pattern Deconstruction
- Using tuples to implement functions with multiple return values
- Methods for iterating over arrays (for loops, iter, enumerate)
2. The Story of a Financial Analyst
(1) The Problem: Storing Data in Disparate Variables
Alice is a financial analyst at the company and needs to store the monthly revenue data for the first half of 2026:
let jan = 120_000; // Jan
let feb = 135_000; // Feb
let mar = 128_000; // Mar
let apr = 142_000; // Apr
let may = 150_000; // May
let jun = 165_000; // Jun
// Want to calculate half-year total?
let sum = jan + feb + mar + apr + may + jun; // Tedious and error-prone
Six months' worth of data is already a pain—what if you had to store 365 days' worth? Would you have to define 365 variables? Passing six variables to a function is already enough to drive you crazy. What's more, you can't use a loop to handle them.
(2) Solution for Rust Arrays
fn main() {
// Half-year revenue: Jan ~ Jun 2026
let revenue: [i32; 6] = [120_000, 135_000, 128_000, 142_000, 150_000, 165_000];
// Total: one line
let sum: i32 = revenue.iter().sum();
println!("2026 H1 total revenue: {} yuan", sum);
// Average
let avg = sum as f64 / revenue.len() as f64;
println!("Monthly average: {:.0} yuan", avg);
// Print each month
for (i, val) in revenue.iter().enumerate() {
println!("Month {}: {} yuan", i + 1, val);
}
}
Arrays store all data of the same type in a single variable—you can access it using indices, iterate through it using loops, pass it to functions, and use iterators to compute and aggregate data. Six lines of code replace 20 lines of scattered variables.
3. Arrays and Tuples
(1) Comparison of Concepts
graph TB
A[Rust fixed-size collections] --> B[Array [T; N]]
A --> C[Tuple (T1, T2, ...)]
B --> D[All elements same type]
B --> E[Compile-time fixed length]
B --> F[Index access: arr[i]]
C --> G[Elements can differ in type]
C --> H[Pattern destructuring]
C --> I[Multiple return values]
(2) Arrays vs. Tuples
| Dimension | Array [T; N] |
Tuple (T1, T2, ...) |
|---|---|---|
| Element Type | Must all be the same | May be different |
| Length | Fixed at compile time (N) | Fixed at compile time (number of elements) |
| Access Method | arr[index] |
tuple.field_index or Deconstruction |
| Use Cases | Sets of data of the same type (e.g., monthly revenue) | Combinations of heterogeneous data (e.g., return values and error codes) |
| Memory | Contiguous memory block | Contiguous memory block (may include alignment padding) |
| Generic Parameters | [T; N] — Type + Length |
(T1, T2) — Type at each position |
| Out-of-Bounds Check | Runtime panic | N/A (field number is known at compile time) |
(3) Quick Reference for Common Array Methods
| Method | Return Type | Description |
|---|---|---|
len() |
usize |
Return array length |
get(i) |
Option<&T> |
Secure Index Access |
get_mut(i) |
Option<&mut T> |
Secure Variable Access |
iter() |
Iter<T> |
Back to Reference Iterators |
contains(&val) |
bool |
Whether a value is included |
sort() |
() |
In-place sorting (requires &mut) |
map(f) |
— | Converted via .iter().map() |
reverse() () In-place rotation (requires &mut) |
(4) Selecting a Fixed-Length Set
| Scenario | Recommended Type | Reason |
|---|---|---|
| Fixed number of elements of the same type | [T; N] Array |
Stack allocation, zero overhead, type-safe |
| Heterogeneous Fixed Combinations | (T1, T2, ...) Tuple |
Combinations of Different Types, Pattern Deconstruction |
| Functions with multiple return values | Tuples | Lightweight; no need to define structures |
| RGB/Coordinates | Tuple Structure | Has a type name, prevents name collisions |
| Large amounts of similar data | Vec<T> |
Dynamic growth, heap allocation |
4. Examples of Arrays and Tuples
▶ Example 1: Array Declaration, Access, and Iteration (Difficulty ⭐)
Output:
First month: 100
Third month: 300
Array length: 6
All values:
<val>
months[<index>] = <value>
Zeros array: <zeros>
// ============================================
// Arrays: declaration, indexing, and iteration
// ============================================
fn main() {
// Type 1: Explicit type annotation
let months: [i32; 6] = [100, 200, 300, 400, 500, 600];
// Type 2: Type inference
let zeros = [0; 5]; // [0, 0, 0, 0, 0], shorthand for [0, 0, 0, 0, 0]
// Access by index (0-based)
println!("First month: {}", months[0]); // 100
println!("Third month: {}", months[2]); // 300
// len() returns the array length
println!("Array length: {}", months.len()); // 6
// Iterate with a for loop
print!("All values: ");
for val in months {
print!("{} ", val);
}
println!();
// Iterate with index using .iter().enumerate()
for (index, value) in months.iter().enumerate() {
println!("months[{}] = {}", index, value);
}
// The shorthand `[val; N]` syntax
println!("Zeros array: {:?}", zeros);
}
Output:
First month: 100
Third month: 300
Array length: 6
All values: 100 200 300 400 500 600
months[0] = 100
months[1] = 200
months[2] = 300
months[3] = 400
months[4] = 500
months[5] = 600
Zeros array: [0, 0, 0, 0, 0]
There are two ways to declare an array:
[initial_value; length]is a convenient shorthand, and[type; length]is the full syntax. Usearr[i]to access elements by index, andfor val in arrto iterate through the array..iter().enumerate()lets you retrieve both the index and the value at the same time.
▶ Example 2: Array Index Out-of-Bounds and Safety Checks (Difficulty ⭐⭐)
Output:
scores[0] = 95
scores[1] = 87
scores[2] = 92
scores[5] = <scores[5]>
Safe get(0): <val>
Index 0 out of bounds
Safe get(5): <val>
Index 5 out of bounds -- safely handled!
scores.get(5) with default: <val>
// ============================================
// Array out-of-bounds: Rust panics at runtime
// ============================================
fn main() {
let scores: [i32; 3] = [95, 87, 92];
// Safe access: within bounds
println!("scores[0] = {}", scores[0]); // OK
println!("scores[1] = {}", scores[1]); // OK
println!("scores[2] = {}", scores[2]); // OK
// Out of bounds: THIS WILL PANIC at runtime
// Uncomment the line below to see the error:
// println!("scores[5] = {}", scores[5]);
//
// Output:
// thread 'main' panicked at src/main.rs:XX:YY:
// index out of bounds: the len is 3 but the index is 5
// Safe alternative: use .get() which returns Option<&T>
let first = scores.get(0); // Some(&95)
let invalid = scores.get(5); // None
match first {
Some(val) => println!("Safe get(0): {}", val),
None => println!("Index 0 out of bounds"),
}
match invalid {
Some(val) => println!("Safe get(5): {}", val),
None => println!("Index 5 out of bounds -- safely handled!"),
}
// Using .get() with a default value
let val = scores.get(5).copied().unwrap_or(-1);
println!("scores.get(5) with default: {}", val); // -1
}
Output:
scores[0] = 95
scores[1] = 87
scores[2] = 92
Safe get(0): 95
Index 5 out of bounds -- safely handled!
scores.get(5) with default: -1
Using
arr[i]directly will cause a runtime panic (crash) if the index is out of bounds. The safe way is to use the.get()method—it returnsOption<&T>, allowing you to gracefully handle out-of-bounds conditions usingmatchorunwrap_orinstead of causing an immediate crash.
▶ Example 3: Creating and Unpacking Tuples, and Function Return Values (Difficulty ⭐⭐)
Output:
Name: <person.0>
Age: <person.1>
Active: <person.2>
Destructured -- <name> is <age> years old, active: <active>
Q1 -- Sum: <count>, Count: <avg>, Avg: <sum>
Nested: <nested>, inner: <(nested.1).1>
Single-element tuple: <single>
Not a tuple: <not_tuple>
// ============================================
// Tuples: creation, destructuring, and return values
// ============================================
// A function that returns a tuple: (sum, count, average)
fn analyze_sales(sales: &[i32]) -> (i32, usize, f64) {
let sum: i32 = sales.iter().sum();
let count = sales.len();
let avg = sum as f64 / count as f64;
(sum, count, avg) // return as a tuple
}
fn main() {
// Tuple with different types: (name, age, active)
let person: (&str, u8, bool) = ("Alice", 30, true);
// Access by field index
println!("Name: {}", person.0);
println!("Age: {}", person.1);
println!("Active: {}", person.2);
// Destructuring: unpack tuple into variables
let (name, age, active) = person;
println!("Destructured -- {} is {} years old, active: {}", name, age, active);
// Tuple as function return value
let q1_sales = [120_000, 135_000, 128_000]; // Jan, Feb, Mar
let (sum, count, avg) = analyze_sales(&q1_sales);
println!("Q1 -- Sum: {}, Count: {}, Avg: {:.0}", sum, count, avg);
// Nested tuples
let nested = (1, (2.5, "hello"), true);
println!("Nested: {:?}, inner: {}", nested, (nested.1).1);
// Single-element tuple: note the trailing comma!
let single = (42,); // tuple with one element
let not_tuple = (42); // just a parenthesized integer
println!("Single-element tuple: {:?}", single);
println!("Not a tuple: {}", not_tuple);
}
Output:
Name: Alice
Age: 30
Active: true
Destructured -- Alice is 30 years old, active: true
Q1 -- Sum: 383000, Count: 3, Avg: 127667
Nested: (1, (2.5, "hello"), true), inner: hello
Single-element tuple: (42,)
Not a tuple: 42
Tuples can store values of different types. You can access their fields using
.0,.1, and.2, or use thelet (a, b, c) = tuplepattern for destructuring. Tuples are particularly well-suited for functions that return multiple values—without the need to define a struct. Note that a single-element tuple must be enclosed in a comma(42,).
▶ Example 4: Iterating Through Arrays and Common Methods (Difficulty ⭐⭐)
Output:
All revenues:
<r>
With .iter():
<r>
Monthly report:
<month_names[i]>: <r> yuan
Growth rate:
<month_names[i]> -> <growth>: <month_names[i - 1]>%
Summary:
Total: <revenue.iter().sum::<i32>()>
Max: <revenue.iter().max().unwrap()>
Min: <revenue.iter().min().unwrap()>
Count > 140k: <revenue.iter().filter(|&&r| r > 140_000).count()>
// ============================================
// Array iteration and common methods
// ============================================
fn main() {
let revenue: [i32; 6] = [120_000, 135_000, 128_000, 142_000, 150_000, 165_000];
let month_names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"];
// Method 1: for-in (by value -- copies each element for i32)
print!("All revenues: ");
for r in revenue {
print!("{} ", r);
}
println!();
// Method 2: .iter() (by reference)
print!("With .iter(): ");
for r in revenue.iter() {
print!("{} ", r);
}
println!();
// Method 3: .iter().enumerate() (index + value)
println!("\nMonthly report:");
for (i, r) in revenue.iter().enumerate() {
println!(" {}: {} yuan", month_names[i], r);
}
// Method 4: for i in 0..len (C-style index)
println!("\nGrowth rate:");
for i in 1..revenue.len() {
let growth = (revenue[i] - revenue[i - 1]) as f64 / revenue[i - 1] as f64 * 100.0;
println!(" {} -> {}: {:.1}%", month_names[i - 1], month_names[i], growth);
}
// Common array methods
println!("\nSummary:");
println!(" Total: {}", revenue.iter().sum::<i32>());
println!(" Max: {}", revenue.iter().max().unwrap());
println!(" Min: {}", revenue.iter().min().unwrap());
println!(" Count > 140k: {}", revenue.iter().filter(|&&r| r > 140_000).count());
}
Output:
All revenues: 120000 135000 128000 142000 150000 165000
With .iter(): 120000 135000 128000 142000 150000 165000
Monthly report:
Jan: 120000 yuan
Feb: 135000 yuan
Mar: 128000 yuan
Apr: 142000 yuan
May: 150000 yuan
Jun: 165000 yuan
Growth rate:
Jan -> Feb: 12.5%
Feb -> Mar: -5.2%
Mar -> Apr: 10.9%
Apr -> May: 5.6%
May -> Jun: 10.0%
Summary:
Total: 840000
Max: 165000
Min: 120000
Count > 140k: 3
There are several ways to iterate over an array:
for val in arr(value copying),arr.iter()(by reference),.enumerate()(indexed), and C-style indexed loops. Arrays also provide a rich set of iterator methods, such as.sum(),.max(),.min(), and.filter().
▶ Example 5: Comprehensive Exercise—Student Grade Statistics (Difficulty ⭐⭐⭐)
Output:
=== Student Report Card ===
Name Sub1 Sub2 Sub3 Average Level
<"-".repeat(44)>
<name> <scores[0]> <scores[1]> <scores[2]> <avg> <grade>
<"-".repeat(44)>
Class-wide Statistics: Lowest=<overall_max>, Highest=<overall_avg>, Average=<overall_min>, >=Average: <above_count> people
// ============================================
// Comprehensive Example: Array + Tuple + Iterators in Practice
// ============================================
fn analyze(scores: &[i32]) -> (i32, i32, f64, i32) {
let min = *scores.iter().min().unwrap_or(&0);
let max = *scores.iter().max().unwrap_or(&0);
let sum: i32 = scores.iter().sum();
let avg = if scores.is_empty() { 0.0 } else { sum as f64 / scores.len() as f64 };
let above_avg = scores.iter().filter(|&&s| s as f64 >= avg).count() as i32;
(min, max, avg, above_avg)
}
fn classify(score: i32) -> &'static str {
match score {
90..=100 => "A",
80..=89 => "B",
70..=79 => "C",
60..=69 => "D",
_ => "F",
}
}
fn main() {
let students = [
("Alice", [95, 88, 92]),
("Bob", [72, 65, 58]),
("Charlie", [85, 90, 78]),
("David", [60, 55, 70]),
];
println!("=== Student Report Card ===");
println!("{:<10} {:>6} {:>6} {:>6} {:>8} {:>6}", "Name", "Sub1", "Sub2", "Sub3", "Average", "Level");
println!("{}", "-".repeat(44));
let mut all_scores: Vec<i32> = Vec::new();
for (name, scores) in &students {
let (min, max, avg, above) = analyze(scores);
let grade = classify(avg as i32);
println!("{:<10} {:>6} {:>6} {:>6} {:>8.1} {:>6}",
name, scores[0], scores[1], scores[2], avg, grade);
all_scores.extend(scores.iter());
}
let (overall_min, overall_max, overall_avg, above_count) = analyze(&all_scores);
println!("{}", "-".repeat(44));
println!("Class-wide Statistics: Lowest={}, Highest={}, Average={:.1}, >=Average: {} people",
overall_min, overall_max, overall_avg, above_count);
let subject_avgs: [f64; 3] = [
students.iter().map(|(_, s)| s[0] as f64).sum::<f64>() / students.len() as f64,
students.iter().map(|(_, s)| s[1] as f64).sum::<f64>() / students.len() as f64,
students.iter().map(|(_, s)| s[2] as f64).sum::<f64>() / students.len() as f64,
];
println!("\nSubject Average: Sub1={:.1}, Sub2={:.1}, Sub3={:.1}",
subject_avgs[0], subject_avgs[1], subject_avgs[2]);
}
Output:
=== Student Report Card ===
Name Sub1 Sub2 Sub3 Average Level
--------------------------------------------
Alice 95 88 92 91.7 A
Bob 72 65 58 65.0 D
Charlie 85 90 78 84.3 B
David 60 55 70 61.7 D
--------------------------------------------
Class-wide Statistics: Lowest=55, Highest=95, Average=76.7, >=Average: 6 people
Subject Average: Sub1=78.0, Sub2=74.5, Sub3=74.5
This example combines the use of arrays and tuples:
[i32; 3]stores the scores for each student in three subjects; the tuple(&str, [i32; 3])combines names and scores;analyzereturns the tuple(min, max, avg, count); and[f64; 3]stores the average score for each subject.
❓ FAQ
[u8; 3] and a slice &[u8]?arr[100] where the array length is also a constant). Dynamic indexing (such as arr[i] where i comes from user input) can only be checked at runtime.[0; 5] Does this syntax work for all types?Copy trait.📖 Summary
- An array
[T; N]is a collection of elements of the same type and fixed length; its size is known at compile time, and it is allocated on the stack. - Arrays are accessed via the
arr[i]index; an out-of-bounds access causes a runtime panic; the.get()method returnsOptionfor safe handling - Array Shorthand
[val; N]Create N elements with the same value (Requires T: Copy) - The tuple
(T1, T2)can store different types, which can be accessed via.0/.1or pattern decomposition. - Tuples are ideal for functions with multiple return values—
fn foo() -> (i32, String) - Choosing Between Tuples and Structures: Use tuples for temporary data and structures for fields with specific meanings
📝 Exercises
- Difficulty ⭐: Declare a
[f64; 7]array of length 7 to store the highest temperatures (in degrees Celsius) for each of the 7 days of the week. Use a loop to find the highest and lowest temperatures. - Difficulty ⭐⭐: Write a function
fn stats(arr: &[i32]) -> (i32, i32, f64)that returns (the minimum, maximum, and average). Test it in the main function using[10, 3, 7, 1, 9, 4]. - Difficulty ⭐⭐⭐: Define an array to store the students' scores
[85, 92, 78, 90, 88]. Manually implement a functionfn rank_scores(scores: &[i32]) -> Vec<(usize, i32, &str)>that returns a list of sorted tuples (rank, score, grade) (Grading rules: >=90 is "A", >=80 is "B", >=70 is "C", and all others are "D").