Quiz 2 - String Transformer
Overview
This quiz tests your understanding of:
- Strings — String manipulation methods
- Vecs — Vectors of tuples
- Modules —
mod,use, andsuper - Enums — Enums with data variants
- Move Semantics — Ownership in function calls
The Problem
Build a transformer function that:
- Takes a vector of
(String, Command)tuples - Applies the command to each string
- Returns a vector of transformed strings
Commands:
Uppercase— Convert to uppercaseTrim— Remove leading/trailing whitespaceAppend(n)— Append “bar” n times
The Full Solution
enum Command {
Uppercase,
Trim,
Append(usize), // Enum variant with data
}
mod my_module {
use super::Command; // Import Command from parent module
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
let mut output = Vec::new();
for (string, command) in input {
let new_string = match command {
Command::Uppercase => string.to_uppercase(),
Command::Trim => string.trim().to_string(),
Command::Append(n) => string + &"bar".repeat(n),
};
output.push(new_string);
}
output
}
}
#[cfg(test)]
mod tests {
use super::{my_module::transformer, Command};
// ...
}Step-by-Step Code Walkthrough
Step 1: Define the Command Enum
enum Command {
Uppercase, // Unit variant (no data)
Trim, // Unit variant (no data)
Append(usize), // Tuple variant with data (how many times to append)
}This enum represents the three possible transformations. Append(usize) holds a number indicating how many times to append “bar”.
Step 2: Create a Module and Import
mod my_module {
use super::Command; // super = parent module (where Command is defined)Why super::Command?
Commandis defined in the parent module (crate root)supermeans “go up one level”- Without this import,
Commandwouldn’t be visible insidemy_module
Step 3: Define the Function Signature
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String>| Part | Meaning |
|---|---|
pub | Public — accessible from outside the module |
input: Vec<(String, Command)> | Vector of tuples, each with a String and Command |
-> Vec<String> | Returns a vector of transformed strings |
Step 4: Iterate and Match
for (string, command) in input {
let new_string = match command {
Command::Uppercase => string.to_uppercase(),
Command::Trim => string.trim().to_string(),
Command::Append(n) => string + &"bar".repeat(n),
};
output.push(new_string);
}Destructuring the tuple: (string, command) extracts both elements.
Step-by-Step Execution
Input:
let input = vec![
("hello".to_string(), Command::Uppercase),
(" all roads lead to rome! ".to_string(), Command::Trim),
("foo".to_string(), Command::Append(1)),
("bar".to_string(), Command::Append(5)),
];Iteration 1: ("hello", Command::Uppercase)
string = "hello"
command = Command::Uppercase
match command {
Command::Uppercase => string.to_uppercase(),
// ^^^^^^^^^^^^^^^^^^^^^^
// "hello".to_uppercase() -> "HELLO"
}
output = ["HELLO"]Iteration 2: (" all roads lead to rome! ", Command::Trim)
string = " all roads lead to rome! "
command = Command::Trim
match command {
Command::Trim => string.trim().to_string(),
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// " all roads lead to rome! ".trim() -> "all roads lead to rome!"
// (removes leading/trailing spaces)
// .to_string() converts &str back to String
}
output = ["HELLO", "all roads lead to rome!"]Iteration 3: ("foo", Command::Append(1))
string = "foo"
command = Command::Append(1)
match command {
Command::Append(n) => string + &"bar".repeat(n),
// ^ ^ ^^^^^^^^^^^^^^^
// | | "bar".repeat(1) -> "bar"
// | | & borrows the repeated string
// | + concatenates (takes ownership of left side)
// n = 1 (destructured from Append(1))
}
// "foo" + &"bar" = "foobar"
output = ["HELLO", "all roads lead to rome!", "foobar"]Iteration 4: ("bar", Command::Append(5))
string = "bar"
command = Command::Append(5)
match command {
Command::Append(n) => string + &"bar".repeat(n),
// "bar" + &"barbarbarbarbar"
// (5 times "bar")
}
// "bar" + "barbarbarbarbar" = "barbarbarbarbarbar"
output = ["HELLO", "all roads lead to rome!", "foobar", "barbarbarbarbarbar"]Key Concepts Explained
1. String Concatenation with +
string + &"bar".repeat(n)+operator takes ownership of left side (string)- Right side must be
&str(borrowed) &"bar".repeat(n)—repeatreturnsString,&borrows it as&str
2. Why .to_string() after .trim()?
string.trim().to_string().trim()returns&str(a slice of the original)- We need to return
String, so.to_string()converts it
3. Module Imports with super
mod tests {
use super::{my_module::transformer, Command};
// ^^^^^
// Goes up to parent module
//
// my_module::transformer — reaches into the sibling module
// Command — defined in parent
}Module hierarchy:
crate root
├── Command (enum)
├── my_module
│ └── transformer (function)
└── tests
└── uses super:: to access siblings and parent
Alternative: Iterator Version
pub fn transformer_iter(input: Vec<(String, Command)>) -> Vec<String> {
input
.into_iter() // Consume the vector, iterate over owned values
.map(|(string, command)| { // Transform each tuple
match command {
Command::Uppercase => string.to_uppercase(),
Command::Trim => string.trim().to_string(),
Command::Append(n) => string + &"bar".repeat(n),
}
})
.collect() // Collect into Vec<String>
}Why into_iter() instead of iter()?
into_iter()takes ownership — we getString, not&String- We need ownership because
+consumes the left-hand String
Concepts Demonstrated
| Concept | How It’s Used |
|---|---|
| Enums with data | Command::Append(usize) |
| Pattern matching | match command { ... } |
| Destructuring | for (string, command) in input |
| Modules | mod my_module { } |
| Imports | use super::Command |
| String methods | .to_uppercase(), .trim(), .repeat() |
| Ownership | string + &... takes ownership of string |
| Visibility | pub fn makes function public |