Options
Type
Option
represents an optional value: every Option is eitherSome
and contains a value, orNone
.enum Option<T> { Some(T), None, }
The
if let
syntax lets you combineif
andlet
into a less verbose way to handle values that match one pattern while ignoring the rest.Using
if let
means less typing, less indentation, and less boilerplate code.Similarly
while let
syntax lets you combinewhile
andlet
.
options1.rs
// This function returns how much icecream there is left in the fridge.
// If it's before 22:00 (24-hour system), then 5 scoops are left. At 22:00,
// someone eats it all, so no icecream is left (value 0). Return `None` if
// `hour_of_day` is higher than 23.
fn maybe_icecream(hour_of_day: u16) -> Option<u16> {
// Complete the function body.
match hour_of_day {
0..=21 => Some(5),
22..=23 => Some(0),
_ => None,
}
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raw_value() {
// Fix this test. How do you get the value contained in the
// Option?
let icecreams = maybe_icecream(12).unwrap();
assert_eq!(icecreams, 5); // Don't change this line.
}
#[test]
fn check_icecream() {
assert_eq!(maybe_icecream(0), Some(5));
assert_eq!(maybe_icecream(9), Some(5));
assert_eq!(maybe_icecream(18), Some(5));
assert_eq!(maybe_icecream(22), Some(0));
assert_eq!(maybe_icecream(23), Some(0));
assert_eq!(maybe_icecream(24), None);
assert_eq!(maybe_icecream(25), None);
}
}
In this exercise we need to return ice cream left by given hour.
Hour
0
until21
return5
scoop left.Hour
22
until23
return0
scoop left.Hour
24
or more returnNone
.
So based on the condition above we can use
match
syntax like this:match hour_of_day { 0..=21 => Some(5), 22..=23 => Some(0), _ => None, } }
And to get the value we can use
unwrap
method.unwrap
can cause panic if the values isNone
so best not to use, we can useunwrap_or
instead to provide default value ifNone
.
options2.rs
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
#[test]
fn simple_option() {
let target = "rustlings";
let optional_target = Some(target);
if let Some(word) = optional_target {
assert_eq!(word, target);
}
}
#[test]
fn layered_option() {
let range = 10;
let mut optional_integers: Vec<Option<i8>> = vec![None];
for i in 1..=range {
optional_integers.push(Some(i));
}
let mut cursor = range;
// Make this a while-let statement. Remember that `Vec::pop()`
// adds another layer of `Option`. You can do nested pattern matching
// in if-let and while-let statements.
while let Some(Some(integer)) = optional_integers.pop() {
assert_eq!(integer, cursor);
cursor -= 1;
}
assert_eq!(cursor, 0);
}
}
In this exercise we need to fix
simple_option
function by usingif let
syntax to safely unwrap/unpack theOption
value.let Some(word) = optional_target { assert_eq!(word, target); }
The code above will unwrap the
optional_target
.If there is
Some
value it will bind it to variableword
and we can use it inside the block.If
None
then it will ignore it.
Second task is to fix
simple_option
by usingwhile let
syntax.while let Some(Some(integer)) = optional_integers.pop() { assert_eq!(integer, cursor); cursor -= 1; }
The code above will do same thing with
if let
, it will check the returned value ofoptional_integers.pop()
.If there is
Some
value there it will bind it tointeger
variable and then goes inside the block.If
None
the loop will stop.
options3.rs
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let optional_point = Some(Point { x: 100, y: 200 });
// Fix the compiler error by adding something to this match statement.
match &optional_point { // Add &
Some(p) => println!("Co-ordinates are {},{}", p.x, p.y),
_ => panic!("No match!"),
}
println!("{optional_point:?}"); // Don't change this line.
}
In this exercise because we want to use the variables
optional_point
further after match we should not move the ownership.Instead we should match the reference so it can be borrowed by adding
&
.
Last updated