第一天上午的练习
数组与 for
循环
(返回练习)
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]; } } return result; } fn pretty_print(matrix: &[[i32; 3]; 3]) { for row in matrix { println!("{row:?}"); } } #[test] fn test_transpose() { let matrix = [ [101, 102, 103], // [201, 202, 203], [301, 302, 303], ]; let transposed = transpose(matrix); assert_eq!( transposed, [ [101, 201, 301], // [102, 202, 302], [103, 203, 303], ] ); } fn main() { let matrix = [ [101, 102, 103], // <-- the comment makes rustfmt add a newline [201, 202, 203], [301, 302, 303], ]; println!("matrix:"); pretty_print(&matrix); let transposed = transpose(matrix); println!("transposed:"); pretty_print(&transposed); }
附加问题
这需要更高级的概念。看起来,我们可以使用切片的切片(&[&[i32]]
)作为输入类型来进行转置,从而使我们的函数能够处理任意大小的矩阵。然而,这很快就会崩溃:返回类型不能是 &[&[i32]]
,因为它需要拥有您返回的数据。
您可以尝试使用类似 Vec<Vec<i32>>
的方式,但这也无法直接工作:从 Vec<Vec<i32>>
转换为 &[&[i32]]
很困难,因此您现在也不能轻松使用 pretty_print
。
了解 trait 和泛型后,我们就可以使用“std::convert::AsRef”trait 来抽象化任何可作为 Slice 引用的内容了。
use std::convert::AsRef; use std::fmt::Debug; fn pretty_print<T, Line, Matrix>(matrix: Matrix) where T: Debug, // A line references a slice of items Line: AsRef<[T]>, // A matrix references a slice of lines Matrix: AsRef<[Line]> { for row in matrix.as_ref() { println!("{:?}", row.as_ref()); } } fn main() { // &[&[i32]] pretty_print(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]); // [[&str; 2]; 2] pretty_print([["a", "b"], ["c", "d"]]); // Vec<Vec<i32>> pretty_print(vec![vec![1, 2], vec![3, 4]]); }
此外,类型本身不会强制要求子切片具有相同的长度,因此这样的变量可能包含一个无效的矩阵。