// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
let mut result = [[0; 3]; 3];
for i in 0..3 {
for j in 0..3 {
result[j][i] = matrix[i][j];
}
}
result
}
fn main() {
let matrix = [
[101, 102, 103], // <-- the comment makes rustfmt add a newline
[201, 202, 203],
[301, 302, 303],
];
println!("Original:");
for row in matrix {
println!("{row:?}");
}
let transposed = transpose(matrix);
println!("\nTransposed:");
for row in transposed {
println!("{row:?}");
}
}
Array Types: The type [[i32; 3]; 3] represents an array of size 3, where
each element is itself an array of 3 i32s. This is how multi-dimensional
arrays are typically represented in Rust.
Initialization: We initialize result with zeros ([[0; 3]; 3]) before
filling it. Rust requires all variables to be initialized before use; there is
no concept of “uninitialized memory” in safe Rust.
Copy Semantics: Arrays of Copy types (like i32) are themselves Copy.
When we pass matrix to the function, it is copied by value. The result
variable is a new, separate array.
Iteration: We use standard for loops with ranges (0..3) to iterate
over indices. Rust also has powerful iterators, which we will see later, but
indexing is straightforward for this matrix transposition.
Mention that [i32; 3] is a distinct type from [i32; 4]. Array sizes are
part of the type signature.
Ask students what would happen if they tried to return matrix directly after
modifying it (if they changed the signature to mut matrix). (Answer: It
would work, but it would return a modified copy, leaving the original in
main unchanged).