Step 5 of 6
while let and slice patterns
while let: loop while a pattern matches
if let runs a block once if a pattern matches. while let keeps running the block as long as the pattern matches, and stops the first time it doesn't. Its classic partner is pop(), which removes the last element of a vector and returns Some(element), or None when the vector is empty:
fn main() {
let mut undo = vec!["type 'a'", "type 'b'", "make bold"];
while let Some(action) = undo.pop() {
println!("undo: {action}");
}
println!("nothing left to undo");
}
undo: make bold
undo: type 'b'
undo: type 'a'
nothing left to undo
That's a stack: last in, first out.
Slice patterns
Arrays and slices have their own patterns, written with square brackets. They match on the length and the elements at the same time:
fn describe(scores: &[u32]) -> String {
match scores {
[] => String::from("no games yet"),
[only] => format!("one game: {only}"),
[first, second] => format!("two games: {first} and {second}"),
[first, .., last] => format!("{} games, first {first}, last {last}", scores.len()),
}
}
fn main() {
println!("{}", describe(&[]));
println!("{}", describe(&[12]));
println!("{}", describe(&[12, 30]));
println!("{}", describe(&[12, 30, 7, 41]));
}
no games yet
one game: 12
two games: 12 and 30
4 games, first 12, last 41
[]matches an empty slice,[only]exactly one element,[first, second]exactly two...inside brackets matches any number of elements (including zero), so[first, .., last]means "at least two".rest @ ..keeps those elements as a slice:[head, rest @ ..]gives the first element and a&[u32]of everything after it.- The compiler checks slice patterns for exhaustiveness too. Here every length is covered.
Parsing commands with slice patterns
Slice patterns are perfect for little command languages. Split a line into words, then match on the words:
fn run(line: &str) -> String {
let words: Vec<&str> = line.split_whitespace().collect();
match words.as_slice() {
[] => String::from("(empty line)"),
["look"] => String::from("You see a crab."),
["go", direction] => format!("You walk {direction}."),
["say", rest @ ..] => format!("You say: {}", rest.join(" ")),
[command, ..] => format!("Unknown command: {command}"),
}
}
fn main() {
for line in ["look", "go north", "say hello there", "", "dance"] {
println!("{}", run(line));
}
}
You see a crab.
You walk north.
You say: hello there
(empty line)
Unknown command: dance
.collect() gathers the words into a Vec<&str> (module 27 covers it), .as_slice() views the vector as a slice so slice patterns apply, and rest.join(" ") glues the remaining words back together with spaces.
Common mistake: matching a Vec directly
Slice patterns need a slice or an array, not a Vec:
fn main() {
let v = vec![1, 2, 3];
match v {
[] => println!("empty"),
_ => println!("some"),
}
}
error[E0529]: expected an array or slice, found `Vec<{integer}>`
Write match v.as_slice() (or match &v[..]).
Your task
Write fn trend(temps: &[i32]) -> String with a slice pattern:
- empty:
"no data" - one reading:
"only T" - otherwise compare the first and last reading:
"rising from A to B","falling from A to B", or"steady at A"if they're equal.
Challenge 2
Write a program for a tiny bank terminal. Each input line is a command:
deposit N: add N to the balance and printbalance: Bwithdraw N: if N is more than the balance printinsufficient funds, otherwise subtract and printbalance: Bbalance: printbalance: B- anything else (including a non-number amount): print
unknown command
The balance starts at 0. Match on words.as_slice() with patterns like ["deposit", amount], and parse the amount with amount.parse::<u32>(), matching on Ok(n) / Err(_).
Challenge 3
Two sensors take turns writing into one list, so readings come in pairs. Write fn pair_sums(values: &[i32]) -> Vec<i32> that adds each pair: [1, 2, 3, 4, 5] gives [3, 7, 5] (a leftover last value is kept as it is).
Use while let with a slice pattern: keep a variable rest (starting as values), and while it matches [a, b, tail @ ..], push a + b and set rest = tail.
Previous: Nested enums and ignoring parts Next: Refutable and irrefutable patterns