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
strmethodtrim_endis 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_withmethod 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
Iteratormethodany. -
anypasses each character to a closure using thecharmethodis_alphabeticto 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 thestrmethodto_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
trueand 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 thematchtests 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 thematchreturns the response for a yell. - If the trimmed input is not a yell, then the next arm of the
matchtests 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
defaultused inswitchstatements 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.