pub fn reply(msg: &str) -> &str {
let message = msg.trim_end();
if message.is_empty() {
return "Fine. Be that way!";
}
let is_questioning = message.ends_with('?');
let is_yelling =
message.chars().any(|ch| ch.is_alphabetic()) && message == message.to_uppercase();
match (is_yelling, is_questioning) {
(true, true) => "Calm down, I know what I'm doing!",
(true, _) => "Whoa, chill out!",
(_, true) => "Sure.",
_ => "Whatever.",
}
}
In this approach you have a match expression to evaluate the conditions.
- First, the
str
methodtrim_end
is used to remove whitespace from the end of the input. - If the trimmed input
is_empty
, then the response for nothing said is returned. - The
ends_with
method is used to determine if the input ends with a question mark. - The first half of the yell condition
message.chars().any(|ch| ch.is_alphabetic())
calls the str
method chars
to create an Iterator
for the characters in the trimmed input.
- The iterated characters are passed into the
Iterator
methodany
. -
any
passes each character to a closure using thechar
methodis_alphabetic
to ensure there is at least one letter character in thestr
. This is because the second half of the condition tests that the uppercased input is the same as the input. If the input were only"123"
it would equal itself uppercased, but without letters it would not be a yell. The uppercasing is done by using thestr
methodto_uppercase
.
The match
tests a tuple constructed from the values for being a question and being a yell.
Since those values are booleans, each arm of the match
tests a pattern of boolean values in the tuple positions.
- If both the yell value in the tuple is
true
and the question part of the tuple istrue
, then the response is returned for a yelled question.
Note that each arm of the match
is a single-line expression, so return
is not needed in the responses returned by the match
arms.
And, since the match
is the last expression in the function, return
is not used before match
.
The last expression can be returned
from a function without using return
and a semicolon.
- If the tuple is not
(true, true)
, then the next arm of thematch
tests if the yell value in the tuple istrue
. It uses the wildcard pattern of_
to disregard the value for the question part of the tuple. If the pattern matches, in other words, if the yell value in the tuple istrue
, then thematch
returns the response for a yell. - If the trimmed input is not a yell, then the next arm of the
match
tests if it is a question. - If so, then the function returns the response for a question.
- Finally, the wildcard pattern is applied to the whole tuple.
This is similar to
default
used inswitch
statements in other languages. It returns "Whatever." no matter what the values in the tuple are.
Note that a match
in Rust must be exhaustive.
This means it must match all conceivable patterns of the value being tested or the code will not compile.
For a boolean value, you can have one arm to match true
and another to match false
,
and the compiler will know that the match
has checked all conceivable patterns for a boolean.
For a value with many possible patterns, such as a u32
, you can have each arm match whatever patterns you care about,
such as 1
and 2
, and then have one final arm using the wildcard pattern to match on everything else.