Day 1 Morning Exercises

Arrays and for Loops

(back to exercise)

  1. // Copyright 2022 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // ANCHOR: transpose
  15. fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
  16. // ANCHOR_END: transpose
  17. let mut result = [[0; 3]; 3];
  18. for i in 0..3 {
  19. for j in 0..3 {
  20. result[j][i] = matrix[i][j];
  21. }
  22. }
  23. return result;
  24. }
  25. // ANCHOR: pretty_print
  26. fn pretty_print(matrix: &[[i32; 3]; 3]) {
  27. // ANCHOR_END: pretty_print
  28. for row in matrix {
  29. println!("{row:?}");
  30. }
  31. }
  32. // ANCHOR: tests
  33. #[test]
  34. fn test_transpose() {
  35. let matrix = [
  36. [101, 102, 103], //
  37. [201, 202, 203],
  38. [301, 302, 303],
  39. ];
  40. let transposed = transpose(matrix);
  41. assert_eq!(
  42. transposed,
  43. [
  44. [101, 201, 301], //
  45. [102, 202, 302],
  46. [103, 203, 303],
  47. ]
  48. );
  49. }
  50. // ANCHOR_END: tests
  51. // ANCHOR: main
  52. fn main() {
  53. let matrix = [
  54. [101, 102, 103], // <-- the comment makes rustfmt add a newline
  55. [201, 202, 203],
  56. [301, 302, 303],
  57. ];
  58. println!("matrix:");
  59. pretty_print(&matrix);
  60. let transposed = transpose(matrix);
  61. println!("transposed:");
  62. pretty_print(&transposed);
  63. }

Bonus question

It requires more advanced concepts. It might seem that we could use a slice-of-slices (&[&[i32]]) as the input type to transpose and thus make our function handle any size of matrix. However, this quickly breaks down: the return type cannot be &[&[i32]] since it needs to own the data you return.

You can attempt to use something like Vec<Vec<i32>>, but this doesn’t work out-of-the-box either: it’s hard to convert from Vec<Vec<i32>> to &[&[i32]] so now you cannot easily use pretty_print either.

Once we get to traits and generics, we’ll be able to use the std::convert::AsRef trait to abstract over anything that can be referenced as a slice.

  1. use std::convert::AsRef;
  2. use std::fmt::Debug;
  3. fn pretty_print<T, Line, Matrix>(matrix: Matrix)
  4. where
  5. T: Debug,
  6. // A line references a slice of items
  7. Line: AsRef<[T]>,
  8. // A matrix references a slice of lines
  9. Matrix: AsRef<[Line]>
  10. {
  11. for row in matrix.as_ref() {
  12. println!("{:?}", row.as_ref());
  13. }
  14. }
  15. fn main() {
  16. // &[&[i32]]
  17. pretty_print(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);
  18. // [[&str; 2]; 2]
  19. pretty_print([["a", "b"], ["c", "d"]]);
  20. // Vec<Vec<i32>>
  21. pretty_print(vec![vec![1, 2], vec![3, 4]]);
  22. }

In addition, the type itself would not enforce that the child slices are of the same length, so such variable could contain an invalid matrix.