We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Shape Your Data: Structs, Enums, Pattern Matching step 8 of 26
The wildcard trap: _ arms freeze your enum against the future
A supervisor process receives text lines describing signals and must turn each line into a status string. Implement:
pub fn handle(events: Vec<String>) -> Vec<String>
Return one status per input line, in the same order. An empty input returns an empty vector.
| line | status |
|---|---|
start |
running |
stop |
halted |
pause |
paused |
resume |
running |
reconnect N |
retrying #N |
| anything else | unknown |
The exact parsing rules, which the starter's parse function already
implements correctly:
- A line is split on whitespace (
str::split_whitespace), so leading, trailing and repeated whitespace is ignored." stop "ishalted. - Keywords are lowercase and case-sensitive:
"Start"isunknown. - A keyword followed by extra words is
unknown:"start now"and"reconnect 3 4"are bothunknown. Nmust parse as au32(0 through 4,294,967,295) usingstr::parse. That accepts an optional leading+and leading zeros, so"reconnect +007"isretrying #7. A missing number, a leading-(even-0), any character other than the ASCII digits0to9after the optional+, or a value aboveu32::MAXmakes the lineunknown.- The number in the output is the parsed value written in plain decimal.
The bug in the starter
The starter's describe function matches on this enum:
enum Signal {
Start,
Stop,
Pause,
Resume,
Reconnect { attempt: u32 },
}
Picture the code as it was in an earlier version, when Signal had only
Start, Stop and Pause. Back then the last arm, _ => "paused", meant
"the remaining variant", which could only be Pause. Since then, someone
added Resume and Reconnect.
Adding those variants did not cause a compile error. The _ pattern (the
wildcard) matches any value, so it silently took over both new variants,
and the starter now reports a resumed process and a reconnection attempt as
paused.
Compare that with a match that names every variant. Rust requires a
match to be exhaustive: every possible value must be handled by some
arm. If every arm names a variant and a new variant is added, every such
match stops compiling with error E0004 ("non-exhaustive patterns") until
you decide what the new variant should do. A wildcard arm always satisfies
the exhaustiveness check, so it also removes that reminder.
Two checks
The starter enables one extra Clippy lint at the top of the file:
#![warn(clippy::wildcard_enum_match_arm)]
This lint warns when a _ arm in a match on an enum covers two or more
of its variants. It belongs to Clippy's restriction group. Lints in that
group are off by default, and Clippy's documentation advises against
enabling the whole group, because some of its lints conflict with each
other or with ordinary Rust style. Enabling one chosen restriction lint, as
here, is the intended use.
Rust submissions are graded on compilation, the test cases and
cargo clippy -- -D warnings. The -D warnings flag turns every warning
into an error, so this lint makes the starter fail Clippy as well as the
resume and reconnect tests.
Keep the attribute in your submission. Deleting it would remove the second check.
Clippy reports a wildcard that covers exactly one variant under a
different lint, match_wildcard_for_single_variants, which is not enabled
here. Naming all five variants avoids both.
When a wildcard is the right choice
The goal is to use a wildcard deliberately, not to avoid it everywhere.
#[non_exhaustive]enums from another crate. This attribute tells users of the enum that new variants may be added in future versions. Outside the crate that defines it, the compiler rejects amatchthat does not include a wildcard (or another catch-all pattern) with E0004, even if you name every variant that exists today.std::io::ErrorKindis an example: matching it outsidestdrequires a_arm. Withwildcard_enum_match_armenabled, Clippy also asks you to name the known variants you mean before that_.- Large enums where many variants share one behavior. A single wildcard arm can be clearer than a long list of variants with identical bodies. The trade-off is that a new variant will get that shared behavior without any compiler error, so this works best when that is the correct default.
Ignoring fields without ignoring variants
Often a _ is written because the arm does not need a variant's data. You
can ignore the data while still naming the variant:
Signal::Reconnect { .. } => "reconnecting".to_string(),
The .. ignores all fields of a struct-like variant, such as
Reconnect { attempt: u32 }. For a tuple-like variant, for example a
hypothetical Message(String, u32), the equivalent is Message(..). Because
the variant is still named, adding another variant to the enum still makes
the match fail to compile until you handle it.
Related Clippy lints
These three lints are in Clippy's pedantic group, which is also off by
default. You can enable them individually, as this problem does with
wildcard_enum_match_arm.
match_wildcard_for_single_variants: a_arm that covers exactly one variant. Clippy suggests naming that variant.match_wild_err_arm: anErr(_)arm that panics, which discards the error value instead of reporting it.single_match_else: a two-armmatchthatif let ... elsewould usually express more simply.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.