We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Shape Your Data: Structs, Enums, Pattern Matching step 11 of 26
Destructuring structs and nested patterns
Summarise order records. Each record is five |-separated fields:
id|name|tier|status|payload.
pub fn summarise(records: Vec<String>) -> Vec<String>
| order | summary |
|---|---|
| gold customer, pending |
1 Ada priority waiting |
| any other customer, pending |
2 Bob waiting |
| shipped |
3 Cy via DHL |
| cancelled |
4 Dee cancelled (fraud) |
| unparseable record |
malformed |
A parser is provided. You write summarise_one, and the constraint is that
it must be one match whose arms are nested struct-and-enum patterns —
no field access, no if, no second match.
Field access is the exception, not the rule
Coming from other languages you will reach for order.customer.name. In
idiomatic Rust the way you read a struct is to take it apart with a
pattern:
let Order { id, customer, status } = order;
and the way you read a struct inside an enum inside a struct is to write that shape out once:
Order {
id,
customer: Customer { name, tier: Tier::Gold },
status: Status::Pending,
} => format!("{id} {name} priority waiting"),
Read that arm carefully. It is simultaneously: a test that the tier is
Gold, a test that the status is Pending, and an extraction of id and
name. Written with ifs and field accesses it is six lines and two
opportunities to get the condition backwards. This is why match scales to
real domain models instead of collapsing into a tower of conditionals.
.. and _ are not the same thing
Beginners conflate them constantly.
-
_ignores exactly one thing — one field, one tuple element, one payload slot. -
..ignores all the remaining fields, and may appear once per pattern.
A struct pattern must account for every field. Miss one and you get
E0027, “pattern does not mention field tier“ — which the starter ships,
so read it. The fix is ... Name a field that does not exist and you get the
mirror-image error, E0026, “does not have a field named z“. Get the arity
of a tuple variant wrong and it is E0023, “this pattern has 1 field, but
the corresponding tuple variant has 2”.
There is also unneeded_field_pattern, an allow-by-default lint for
Customer { name, tier: _ } where Customer { name, .. } says it better.
Matching a reference
summarise_one takes &Order, so the patterns match a reference to an
Order. Under Rust 2024’s binding modes, matching a &T with a
non-reference pattern binds the fields by reference automatically: name
comes out as &String, not String. That is what you want — moving a
String out of a borrowed struct is E0507, “cannot move out of a shared
reference”, and moving it out of an owned one leaves you with E0382 if you
touch the rest afterwards.
One lint that will surprise you
infallible_destructuring_match is on by default. It fires on this:
let n = match wrapper { Wrapper::Only(n) => n };
A single-variant enum has nothing to choose between, so match is theatre.
Write let Wrapper::Only(n) = wrapper; instead. The general principle is the
same one behind single_match and match_single_binding: match is for
choosing. When there is no choice, a let is the honest form.
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.