We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Shape Your Data: Structs, Enums, Pattern Matching step 10 of 26
Binding with @, and what or-patterns demand of bindings
Put each number in a bucket and report both the bucket and the number.
pub fn bucket(values: Vec<i64>) -> Vec<String>
Anything up to 9 is small, 10..=99 is mid, 100 and above is
large. bucket(vec![0, 50, 1000]) gives
["small:0", "mid:50", "large:1000"].
Part one: @ binds the value you just tested
The naive way to write this is a range test and a separate read of the same value — often with a guard, and always with the number written twice:
match value {
n if (..=9).contains(&n) => Bucket::Small(value), // clumsy
// ...
}
The pattern language already has this. name @ pattern matches pattern
and binds the matched value to name:
match value {
n @ ..=9 => Bucket::Small(n),
n @ 10..=99 => Bucket::Mid(n),
n => Bucket::Large(n),
}
Note ..=9 — a half-open range pattern, no lower bound needed. And note the
last arm: a bare identifier is a binding that matches anything, which is what
makes this exhaustive without a _.
@ is the pattern feature learners most reliably fail to discover. Once you
have it you will use it constantly, especially in nested positions:
Message::Resize { width: w @ 1..=4096, .. } tests and captures in one move.
One caveat: @ on a payload that is not Copy moves it. Bind a
String with s @ .. inside a &-matched structure and you will meet
E0507, “cannot move out of a shared reference”.
Part two: what or-patterns demand
payload pulls the number out of a Bucket regardless of which bucket it is:
match bucket {
Bucket::Small(n) | Bucket::Mid(n) | Bucket::Large(n) => *n,
}
One arm, three alternatives, one binding. For that to be well-defined the compiler enforces three rules, and the starter breaks the first of them so you meet the error:
-
Every alternative must bind exactly the same names. Miss one and you
get
E0408, “variablemis not bound in all patterns” — and you get it from both directions, once for the name that is missing from some alternatives and once for the name that is missing from the others. Downstream,E0381(“used bindingnis possibly-uninitialized”) piles on, because the compiler cannot promise the binding exists. -
The same name must have the same type in every alternative. Otherwise
E0409, “variablexis bound inconsistently across alternatives”. -
A name may be bound only once per alternative.
(a, a)isE0416, “identifierais bound more than once”.
These are not arbitrary. A pattern’s job is to produce a set of bindings; if
which alternative matched changed which bindings exist or what type they
had, no code after the => could be type-checked at all.
Nesting | where the choice actually is
Beginners write Some(1) | Some(2) | Some(3). Rust lets you put the
alternation exactly where the variation is: Some(1 | 2 | 3). The
unnested_or_patterns lint exists to push you toward the tighter form,
though it is allow-by-default so the gate will not do it for you.
redundant_pattern is on by default, and catches x @ _ — binding
everything and also writing @, where a bare x says the same thing.
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.