We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Shape Your Data: Structs, Enums, Pattern Matching step 9 of 26
Literal, range and or-patterns
Classify every character of a string into one of six buckets.
pub fn classify_chars(s: String) -> Vec<String>
| bucket | members |
|---|---|
digit |
0–9 |
lower |
a–z |
upper |
A–Z |
space |
space, tab, newline, carriage return |
punct |
the remaining printable ASCII |
other |
everything else, including all non-ASCII |
Use only literal, range and or-patterns. No is_ascii_digit, no
is_alphabetic, no helper methods. The point is the pattern language.
match stops being a switch statement here
A pattern can be a literal ('q'), an inclusive range ('a'..='z'),
a half-open range (..=9, 10..), or several alternatives joined with
|:
match c {
'0'..='9' => "digit",
' ' | '\t' | '\n' | '\r' => "space",
_ => "other",
}
Two things to know about | that people discover late:
It alternates at any nesting depth. Some(1 | 2 | 3) is legal and is
what you want — not Some(1) | Some(2) | Some(3). The alternatives sit
wherever the choice actually is.
Ranges over char are ranges over Unicode scalar values. 'a'..='z'
works because ASCII letters happen to be contiguous. 'a'..='ÿ' compiles and
covers a mess. And char has 1,112,064 legal values, so a match on a char
built from a handful of ranges is nowhere near exhaustive — the starter proves
it. Read what rustc prints:
error[E0004]: non-exhaustive patterns: `'\0'..='\u{8}'`, `'\u{b}'..='\u{c}'`,
`'\u{e}'..='\u{1f}'` and 5 more not covered
That message is doing real work. It is telling you exactly which slices of the code-point space you forgot, control characters included.
The ASCII layout, because you will need it
0x20 ' ' 0x21-0x2F ! " # $ % & ' ( ) * + , - . /
0x30-0x39 0-9 0x3A-0x40 : ; < = > ? @
0x41-0x5A A-Z 0x5B-0x60 [ \ ] ^ _ `
0x61-0x7A a-z 0x7B-0x7E { | } ~
Punctuation is the four gaps between the alphanumeric blocks. Four ranges,
joined with |, in one arm.
Arms are tried in order
The first matching arm wins, and only the first. Overlapping arms are legal
and sometimes exactly what you want, but if a later arm is completely
covered by an earlier one you get an unreachable_pattern warning — which
under -D warnings is a build failure. match_overlapping_arm and
almost_complete_range (which spots 'a'..='y' where you almost certainly
meant 'z') are the clippy lints in this area.
A lint with a sharp edge, honestly described
manual_range_patterns is on by default and rewrites 1 | 2 | 3 | 4 into
1..=4. Verified on clippy 0.1.95: it fires for integer or-patterns and
is silent for char ones — so '0' | '1' | ... | '9' passes the gate
even though '0'..='9' is plainly better. Take that as a reminder that a
clean clippy run is a floor, not a ceiling. Write the range anyway.
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.