Day 1 Exercises
Arrays and for
Loops
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); }
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.
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]]); }
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.
Luhn Algorithm
pub fn luhn(cc_number: &str) -> bool { let mut sum = 0; let mut double = false; let mut digit_seen = 0; for c in cc_number.chars().filter(|&f| f != ' ').rev() { if let Some(digit) = c.to_digit(10) { if double { let double_digit = digit * 2; sum += if double_digit > 9 { double_digit - 9 } else { double_digit }; } else { sum += digit; } double = !double; digit_seen += 1; } else { return false; } } if digit_seen < 2 { return false; } sum % 10 == 0 } fn main() { let cc_number = "1234 5678 1234 5670"; println!( "Is {cc_number} a valid credit card number? {}", if luhn(cc_number) { "yes" } else { "no" } ); } #[test] fn test_non_digit_cc_number() { assert!(!luhn("foo")); assert!(!luhn("foo 0 0")); } #[test] fn test_empty_cc_number() { assert!(!luhn("")); assert!(!luhn(" ")); assert!(!luhn(" ")); assert!(!luhn(" ")); } #[test] fn test_single_digit_cc_number() { assert!(!luhn("0")); } #[test] fn test_two_digit_cc_number() { assert!(luhn(" 0 0 ")); } #[test] fn test_valid_cc_number() { assert!(luhn("4263 9826 4026 9299")); assert!(luhn("4539 3195 0343 6467")); assert!(luhn("7992 7398 713")); } #[test] fn test_invalid_cc_number() { assert!(!luhn("4223 9826 4026 9299")); assert!(!luhn("4539 3195 0343 6476")); assert!(!luhn("8273 1232 7352 0569")); }