13 Rustlings Quiz2 Solution
Quiz 2
It's quiz time again! We've been through a bunch of different exercises and now we'll be putting in action what we've learned.
quiz2.rs
// quiz2.rs
// This is a quiz for the following sections:
// - Strings
// - Vecs
// - Move semantics
// - Modules
// - Enums
// Let's build a little machine in the form of a function.
// As input, we're going to give a list of strings and commands. These commands
// determine what action is going to be applied to the string. It can either be:
// - Uppercase the string
// - Trim the string
// - Append "bar" to the string a specified amount of times
// The exact form of this will be:
// - The input is going to be a Vector of a 2-length tuple,
// the first element is the string, the second one is the command.
// - The output element is going to be a Vector of strings.
// No hints this time!
// I AM NOT DONE
pub enum Command {
Uppercase,
Trim,
Append(usize),
}
mod my_module {
use super::Command;
// TODO: Complete the function signature!
pub fn transformer(input: ???) -> ??? {
// TODO: Complete the output declaration!
let mut output: ??? = vec![];
for (string, command) in input.iter() {
// TODO: Complete the function body. You can do it!
}
output
}
}
#[cfg(test)]
mod tests {
// TODO: What do we need to import to have `transformer` in scope?
use ???;
use super::Command;
#[test]
fn it_works() {
let output = transformer(vec![
("hello".into(), Command::Uppercase),
(" all roads lead to rome! ".into(), Command::Trim),
("foo".into(), Command::Append(1)),
("bar".into(), Command::Append(5)),
]);
assert_eq!(output[0], "HELLO");
assert_eq!(output[1], "all roads lead to rome!");
assert_eq!(output[2], "foobar");
assert_eq!(output[3], "barbarbarbarbarbar");
}
}
We have instructions in the comments and four TODOs
annotated in the code. Let's first take a look at the instructions and make sure we understand what is being asked of us.
General Instructions
- We're building a function
- We're inputing a list of strings and commands into our function
- The commands can be
- Uppercase the string
- Trim the string
- Append "bar" to the string a specified amount of times
Details
- Input will be a Vector of a 2-length tuple
- First element is a string, second one is a command
- Output is going to be a Vector of strings.
quiz2.rs errors
⚠️ Compiling of exercises/quiz2.rs failed! Please try again. Here's the output:
error: expected identifier, found `)`
--> exercises/quiz2.rs:33:34
|
33 | pub fn transformer(input: ???) -> ??? {
| ^ expected identifier
error: expected identifier, found `{`
--> exercises/quiz2.rs:33:43
|
33 | pub fn transformer(input: ???) -> ??? {
| ^ expected identifier
error: aborting due to 2 previous errors
Our errors are pretty self explanatory we're missing code, so no surprises there.
Let's take a look at the specific areas that need to be completed.
Todo in transformer
function
mod my_module {
use super::Command;
// TODO: Complete the function signature!
pub fn transformer(input: ???) -> ??? {
// TODO: Complete the output declaration!
let mut output: ??? = vec![];
for (string, command) in input.iter() {
// TODO: Complete the function body. You can do it!
}
output
}
}
A quick look at our todo's here show us that we have to:
- Complete the signature
- Complete the
output
variable declaration - Complete the function body.
Test Todo
#[cfg(test)]
mod tests {
// TODO: What do we need to import to have `transformer` in scope?
use ???;
use super::Command;
- Our fourth todo is to make sure we have
transformer
in scope.
quiz2.rs solution
Completing the Function Signature
Let's go through these in order, let's look at the function signature, and our instructions which tell us that: input will be a Vector of a 2-length tuple
pub fn transformer(input: ???) -> ??? {
So a vector is declared as Vec<>
but in this particular case we need a tuple stored inside of the vector which would make it look something like this Vec<(,)>
when empty, but we know that we need to pass in 2 items as we're told in our instructions: first element is a string, second one is a command
so to complete it, it should look something like this: Vec<(String, command)>
.
Now, let's look at the return value which we were told is: output is going to be a Vector of strings with that we can complete our function signature to look like this:
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
This should complete our function signature for transformer
.
Completing the output
declaration
let mut output: ??? = vec![]
Here we have an incomplete variable declaration, we need to provide the type to complete it. If we reference our notes, we've been told that we should be expecting a Vector of strings, so we should be able to add that to our declaration to complete the line.
let mut output: Vec<String> = vec![]
Completing the Function Body
Now, let's consider what needs to be completed in the function body and the actions that need to be performed on the strings based on the commands. Remember, the available commands are Uppercase
, Trim
, and Append
, that are defined in our Command
enum.
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
let mut output: Vec<String> = vec![];
for (string, command) in input.iter() {
// we use a match statement to match to the correct command
let modified_string = match command {
// taking each case and using the appropriate method
Command::Uppercase => string.to_uppercase(), // uppercase the string
Command::Trim => string.trim().to_string(), // trim the string
Command::Append(count) => { // appending
let appended_string = format!("{}{}", string, "bar".repeat(*count));
appended_string
}
};
output.push(modified_string); // Add the modified string to the output vector
}
output // Return the output vector
}
So one of the ways that we know we can use enums is with match statements, we know that if something matches a certain criteria we can perform certain actions and return a value. So matching each Command
in the enum
using the Command::Uppercase =>
style matching we can perform an action for each match.
In the first two cases, it's pretty simple all we have to do is call the appropriate method like .to_upercase()
in the first match and .trim()
(along with the .to_string()
method on in Trim
) but when we get to Append
we have to perform an additional manipulation.
Appending
If we look back to our instructions we have to Append "bar" to a string a specified amount of times. So we can simply call a method or two and be done with our string. We have to add the logic to be able to do this. First let's create a new variable called appended_string
and let's use the format!
macro to put it into the format we want to use. In this case we use:
format!("{}{}", string, "bar".repeat(*count));
This takes the original string, and concatenates "bar" to it by using .repeat
we repeat it by the count
we define in the Command::Append(count)
branch. Finally, we return the appended_string
, reminder this only happens if the Append
arm matches.
So at this point we have one of the three arms of the match inside of modified_string
at this point we need to push this modified string to our mut output
Vec. Once that is completed we can then return our output
variable with the correctly modified string.
Importing transformer
Our last TODO
is in our tests and it should be fairly simple to fix. We just have to use the full path of our function and remember to use the crate
keyword that looks at the crate root, which is where our file is. After crate we must use the ::
double colon symbols which are equivalent to using /
in traditional file path systems. So for our purposes we need: use crate::my_module::transformer;
to be able to use the function in our tests.
Here's the full updated code:
pub enum Command {
Uppercase,
Trim,
Append(usize),
}
mod my_module {
use super::Command;
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
let mut output: Vec<String> = vec![];
for (string, command) in input.iter() {
let modified_string = match command {
Command::Uppercase => string.to_uppercase(),
Command::Trim => string.trim().to_string(),
Command::Append(count) => {
let appended_string = format!("{}{}", string, "bar".repeat(*count));
appended_string
}
};
output.push(modified_string);
}
output
}
}
#[cfg(test)]
mod tests {
use super::Command;
use crate::my_module::transformer;
#[test]
fn it_works() {
let output = transformer(vec![
("hello".into(), Command::Uppercase),
(" all roads lead to rome! ".into(), Command::Trim),
("foo".into(), Command::Append(1)),
("bar".into(), Command::Append(5)),
]);
assert_eq!(output[0], "HELLO");
assert_eq!(output[1], "all roads lead to rome!");
assert_eq!(output[2], "foobar");
assert_eq!(output[3], "barbarbarbarbarbar");
}
}
Conclusion
In this post, we tackled Quiz 2, which required us to build a function that performs different actions on a list of strings based on given commands. We were instructed to uppercase a string, trim it, or append "bar" to it a specified number of times.
We began by analyzing the provided instructions and understanding the requirements. The input was expected to be a vector of tuples, where each tuple consisted of a string and a command. The output was to be a vector of strings.
Next, we addressed the incomplete parts of the code. We completed the function signature by specifying the input and output types as Vec<(String, Command)>
and Vec<String>
respectively.
In the function body, we utilized a match
statement to match the command type and performed the corresponding action on the string. For the Append
command, we used the format!
macro to concatenate "bar" to the string a specified number of times.
We then added the modified strings to the output
vector and returned it at the end of the function.
Lastly, we resolved the test-related task by importing the transformer
function into the test module using the full path: use crate::my_module::transformer;
.
With these modifications, the code was successfully compiled and passed the provided tests.
Overall, this quiz allowed us to apply our knowledge of strings, vectors, move semantics, modules, and enums in Rust to build a functional machine. It reinforced our understanding of Rust concepts and helped us gain more confidence in utilizing them.