const ANSWERS: &'static [&'static str] = &[
"Whatever.",
"Sure.",
"Whoa, chill out!",
"Calm down, I know what I'm doing!",
];
pub fn reply(msg: &str) -> &str {
let message = msg.trim_end();
if message.is_empty() {
return "Fine. Be that way!";
}
let is_questioning = if message.ends_with('?') { 1 } else { 0 };
let is_yelling =
if message.chars().any(|ch| ch.is_alphabetic()) && message == message.to_uppercase() {
2
} else {
0
};
ANSWERS[is_questioning + is_yelling]
}
In this approach you define an array that contains Bob’s answers, and each condition is given a score. The correct answer is selected from the array by using the score as the array index.
The array is defined using the static
lifetime annotation for a reference to an array of str
references.
static
means that the value will live for the life of the program.
The static
annotation can be removed, as described in the Shortening section.
The reference symbols &
are needed because the compiler must know the size of each binding.
The compiler doesn't know the size of each str
, but it does know the size of a reference to a str
,
which is the size of a pointer for that platform.
For a 64-bit system, the size of a pointer is 64 bits.
So, each str
is defined as a str
reference (&str
).
The array itself is defined as a reference, since the compiler does not know the size of the whole array and its contents.
-
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. If so,is_questioning
is given the value1
, otherwise it is given the value0
. -
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
. If the input is a yell, thenis_yelling
is given the value2
, otherwise it is given the value0
.
The final expression returns the value in the ANSWERS
array at the index of the combined values for is_questioning
and is_yelling
.
Note that the final line is just ANSWERS[is_questioning + is_yelling]
This is because the last expression can be returned
from a function without using return
and a semicolon.
is_yelling | is_questioning | Index | Answer |
---|---|---|---|
false |
false |
0 + 0 = 0 | "Whatever." |
false |
true |
0 + 1 = 1 | "Sure." |
true |
false |
2 + 0 = 2 | "Whoa, chill out!" |
true |
true |
2 + 1 = 3 | "Calm down, I know what I'm doing!" |
Shortening
For defining the array the static
lifetime specifiers can be dropped, like so
const ANSWERS: &[&str] = &[
"Whatever.",
"Sure.",
"Whoa, chill out!",
"Calm down, I know what I'm doing!",
];
A lifetime specifier doesn't change the actual lifetime of a binding. It just makes the lifetime explicit. When the compiler can figure out the lifetime, then the annotation can be dropped, which is called lifetime elision.