We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Shape Your Data: Structs, Enums, Pattern Matching step 12 of 26
Slice and array patterns, and rest @ ..
Two functions, both graded.
pub fn shrink(tokens: Vec<String>) -> String
pub fn windows_sum(v: Vec<i64>) -> Vec<i64>
shrink folds a list from both ends inwards:
| tokens | result |
|---|---|
[] |
empty |
["a"] |
a |
["a","b"] |
a+b |
["a","b","c"] |
a(b)c |
["a","b","c","d"] |
a(b+c)d |
["a","b","c","d","e"] |
a(b(c)d)e |
That is: with three or more tokens, take the first and the last, and put the recursively-shrunk middle in brackets between them.
windows_sum returns the sum of every consecutive triple. [1,2,3,4]
gives [6, 9]; fewer than three elements gives []. Write it without
indexing — no v[i], no bounds arithmetic.
Slice patterns turn index code into declarative code
match tokens {
[] => ..., // exactly zero
[only] => ..., // exactly one
[a, b] => ..., // exactly two
[first, mid @ .., last] => ..., // two or more, mid may be empty
}
Compare with the version you would otherwise write: a len() check, three
branches, tokens[0], tokens[tokens.len() - 1], and a slice expression
with two off-by-one opportunities. The pattern version has none of those,
cannot panic, and reads as the case analysis it is.
rest @ .. is the @ binding from the previous item applied to a
sub-slice: .. matches “any number of elements” and rest @ names them.
There may be at most one .. in a slice pattern — otherwise the
compiler could not tell where the middle begins.
This is also Rust’s natural answer to head/tail recursion: [first, rest @ ..]
is (x:xs) in a language with cons cells, without the cons cells.
The error you will hit first
error[E0529]: expected an array or slice, found `Vec<String>`
Slice patterns match [T; N] and [T]. A Vec<T> is neither; it is a
struct that derefs to a slice. Deref coercion happens at method calls and
at coercion sites, and a match scrutinee is not one of them. So you must
produce a slice yourself:
match v.as_slice() { ... } // or match &v[..] { ... }
The starter ships this error because it is the first thing everyone hits.
Fixing it properly also changes the shape of the recursion: the helper wants
to take &[String], not Vec<String>, so each recursive call is a
sub-slice with no allocation at all.
Binding modes, which bit people
Under Rust 2024, matching a &[T] with [first, .., last] binds first
and last as &T, not T. That is why the single-element arm needs a
.clone() to produce an owned String, and why a + b + c in
windows_sum is adding three &i64s (which works — the Add impls cover
references).
Half-open ranges inside slice patterns
If you ever nest a range pattern in a slice pattern, parenthesise it:
[(1..), ..]. Without the parentheses the parser cannot tell your ..
apart from the slice’s ...
A note on indexing
clippy::indexing_slicing (allow-by-default, restriction) flags every
v[i] and &v[a..b] as a potential panic. It is deliberately not on here —
it would reject far too much ordinary code — but the reason it exists is
exactly the reason to prefer slice patterns: an index can be out of bounds,
and a pattern cannot. (clippy::match_on_vec_items used to cover the
Vec-specific case and has been removed; clippy’s own removal note says
indexing_slicing covers it.)
Remember the grade is compile + tests + clippy -D warnings.
Loading visualization…
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.