Going through rustlings for the first time

ex(12): options

options3 is a little harder to grok: the key is to understand that pattern
matching is a form of assignment, so matching on optional_point to Some(p)
actually moves the Point out of the Option into the variable `p`.

Of the two solutions, I think I'd prefer matching on &optional_point because it
feels more explicit that we are borrowing during the Some(p) pattern matching.

authored by Chay Choong and committed by chay.dev 025e5c98 7e3283f9

Changed files
+114 -14
exercises
solutions
+5 -2
.rustlings-state.txt
··· 1 1 DON'T EDIT THIS FILE! 2 2 3 - options1 3 + errors1 4 4 5 5 intro1 6 6 intro2 ··· 48 48 hashmaps1 49 49 hashmaps2 50 50 hashmaps3 51 - quiz2 51 + quiz2 52 + options1 53 + options2 54 + options3
+6 -1
exercises/12_options/options1.rs
··· 4 4 // `hour_of_day` is higher than 23. 5 5 fn maybe_icecream(hour_of_day: u16) -> Option<u16> { 6 6 // TODO: Complete the function body. 7 + match hour_of_day { 8 + 0..=21 => Some(5), 9 + 22..=23 => Some(0), 10 + _ => None, 11 + } 7 12 } 8 13 9 14 fn main() { ··· 18 23 fn raw_value() { 19 24 // TODO: Fix this test. How do you get the value contained in the 20 25 // Option? 21 - let icecreams = maybe_icecream(12); 26 + let icecreams = maybe_icecream(12).unwrap(); 22 27 23 28 assert_eq!(icecreams, 5); // Don't change this line. 24 29 }
+6 -4
exercises/12_options/options2.rs
··· 10 10 let optional_target = Some(target); 11 11 12 12 // TODO: Make this an if-let statement whose value is `Some`. 13 - word = optional_target { 13 + if let Some(word) = optional_target { 14 14 assert_eq!(word, target); 15 15 } 16 16 } ··· 29 29 // TODO: Make this a while-let statement. Remember that `Vec::pop()` 30 30 // adds another layer of `Option`. You can do nested pattern matching 31 31 // in if-let and while-let statements. 32 - integer = optional_integers.pop() { 33 - assert_eq!(integer, cursor); 34 - cursor -= 1; 32 + while let Some(integer) = optional_integers.pop() { 33 + if let Some(integer) = integer { 34 + assert_eq!(integer, cursor); 35 + cursor -= 1; 36 + } 35 37 } 36 38 37 39 assert_eq!(cursor, 0);
+1 -1
exercises/12_options/options3.rs
··· 8 8 let optional_point = Some(Point { x: 100, y: 200 }); 9 9 10 10 // TODO: Fix the compiler error by adding something to this match statement. 11 - match optional_point { 11 + match &optional_point { 12 12 Some(p) => println!("Co-ordinates are {},{}", p.x, p.y), 13 13 _ => panic!("No match!"), 14 14 }
+37 -2
solutions/12_options/options1.rs
··· 1 + // This function returns how much icecream there is left in the fridge. 2 + // If it's before 22:00 (24-hour system), then 5 scoops are left. At 22:00, 3 + // someone eats it all, so no icecream is left (value 0). Return `None` if 4 + // `hour_of_day` is higher than 23. 5 + fn maybe_icecream(hour_of_day: u16) -> Option<u16> { 6 + match hour_of_day { 7 + 0..=21 => Some(5), 8 + 22..=23 => Some(0), 9 + _ => None, 10 + } 11 + } 12 + 1 13 fn main() { 2 - // DON'T EDIT THIS SOLUTION FILE! 3 - // It will be automatically filled after you finish the exercise. 14 + // You can optionally experiment here. 15 + } 16 + 17 + #[cfg(test)] 18 + mod tests { 19 + use super::*; 20 + 21 + #[test] 22 + fn raw_value() { 23 + // Using `unwrap` is fine in a test. 24 + let icecreams = maybe_icecream(12).unwrap(); 25 + 26 + assert_eq!(icecreams, 5); 27 + } 28 + 29 + #[test] 30 + fn check_icecream() { 31 + assert_eq!(maybe_icecream(0), Some(5)); 32 + assert_eq!(maybe_icecream(9), Some(5)); 33 + assert_eq!(maybe_icecream(18), Some(5)); 34 + assert_eq!(maybe_icecream(22), Some(0)); 35 + assert_eq!(maybe_icecream(23), Some(0)); 36 + assert_eq!(maybe_icecream(24), None); 37 + assert_eq!(maybe_icecream(25), None); 38 + } 4 39 }
+35 -2
solutions/12_options/options2.rs
··· 1 1 fn main() { 2 - // DON'T EDIT THIS SOLUTION FILE! 3 - // It will be automatically filled after you finish the exercise. 2 + // You can optionally experiment here. 3 + } 4 + 5 + #[cfg(test)] 6 + mod tests { 7 + #[test] 8 + fn simple_option() { 9 + let target = "rustlings"; 10 + let optional_target = Some(target); 11 + 12 + // if-let 13 + if let Some(word) = optional_target { 14 + assert_eq!(word, target); 15 + } 16 + } 17 + 18 + #[test] 19 + fn layered_option() { 20 + let range = 10; 21 + let mut optional_integers: Vec<Option<i8>> = vec![None]; 22 + 23 + for i in 1..=range { 24 + optional_integers.push(Some(i)); 25 + } 26 + 27 + let mut cursor = range; 28 + 29 + // while-let with nested pattern matching 30 + while let Some(Some(integer)) = optional_integers.pop() { 31 + assert_eq!(integer, cursor); 32 + cursor -= 1; 33 + } 34 + 35 + assert_eq!(cursor, 0); 36 + } 4 37 }
+24 -2
solutions/12_options/options3.rs
··· 1 + #[derive(Debug)] 2 + struct Point { 3 + x: i32, 4 + y: i32, 5 + } 6 + 1 7 fn main() { 2 - // DON'T EDIT THIS SOLUTION FILE! 3 - // It will be automatically filled after you finish the exercise. 8 + let optional_point = Some(Point { x: 100, y: 200 }); 9 + 10 + // Solution 1: Matching over the `Option` (not `&Option`) but without moving 11 + // out of the `Some` variant. 12 + match optional_point { 13 + Some(ref p) => println!("Co-ordinates are {},{}", p.x, p.y), 14 + // ^^^ added 15 + _ => panic!("No match!"), 16 + } 17 + 18 + // Solution 2: Matching over a reference (`&Option`) by added `&` before 19 + // `optional_point`. 20 + match &optional_point { 21 + Some(p) => println!("Co-ordinates are {},{}", p.x, p.y), 22 + _ => panic!("No match!"), 23 + } 24 + 25 + println!("{optional_point:?}"); 4 26 }