Problem overview
The function shout receives a vector of lowercase words, words, and returns a new vector in which every word is shouted: written in capital letters with ! after it. The order stays the same and a repeated word is shouted each time.
For ["hey", "you"] the answer is ["HEY!", "YOU!"]. For ["go"] it is ["GO!"], and for ["no", "no", "no"] it is ["NO!", "NO!", "NO!"].
Approach
The job is the same for every word: turn one word into a new one. Iterators have a method for that, map, which applies a closure to each item and produces the results in the same order. Then collect() gathers those results into a vector.
Calling iter() on the vector borrows it, so the closure sees each word as a reference and the original vector is left untouched. For each word, to_uppercase() builds a new String in capital letters, and adding "!" with + appends the mark to that new string.
Step by step
- Name the result type. Write
let shouted: Vec<String> = .... The type after the name tellscollect()what to build; without it the compiler reports "type annotations needed", becausecollect()can produce many kinds of collection. - Start the chain with
words.iter(). - Map each word with
|word| word.to_uppercase() + "!". The left side of+is an ownedString, which is what Rust requires: adding to a borrowed reference does not compile. - End with
collect()to build the vector. - Return
shouted. The input vector did not change; the answer is a new one.
The solution in Rust
impl Solution {
fn shout(words: Vec<String>) -> Vec<String> {
let shouted: Vec<String> = words.iter().map(|word| word.to_uppercase() + "!").collect();
return shouted;
}
}
Iterators in Rust are lazy: map alone does nothing until something consumes the iterator, and collect() is what runs the whole chain. A closure with one parameter is written between vertical bars, and its last expression is its result, so no return is needed inside it.
About to_uppercase
The method to_uppercase() never changes the original text, because strings are not edited in place this way. It returns a new String. For the lowercase letters a to z used in this lesson, the result is simply the capital version of each letter. The method also handles other alphabets, and a single letter may turn into more than one in some of them, which is why it returns a String and not a single character.
Another way
format!("{}!", word.to_uppercase()) builds the same string without using +. Both forms give ["HEY!", "YOU!"] for the first example.
Testing
The first and third examples give:
["HEY!", "YOU!"]
["NO!", "NO!", "NO!"]
The words are borrowed by iter(), so after the call the input vector still holds ["hey", "you"]. If the caller no longer needs the input vector, into_iter() would hand over the words themselves instead of borrowing them; the result for this problem is the same.
Edge cases and common mistakes
- Forgetting the type on
shouted. The compiler cannot guess the collection and stops with an error. - Writing
word + "!"with the loop's reference. The compiler says it cannot add a&strto a&String, and notes that concatenation needs an ownedStringon the left.to_uppercase()provides one. - Forgetting
collect(). The result would be an iterator, not a vector.
