rustiteratorrust-rustlings

How can I transform a vector of strings in Rust with map and then join the strings with flat_map in one line?


I'm doing the second level of rustlings for the iterator chapter.

I found the following solution for step 3, and now I would like to chain map and flat_map.

// Step 3.
// Apply the `capitalize_first` function again to a slice of string slices.
// Return a single string.
// ["hello", " ", "world"] -> "Hello World"
pub fn capitalize_words_string(words: &[&str]) -> String {
    let capitalized: Vec<String> = words.iter().map(|word| capitalize_first(&word)).collect();
    capitalized.iter().flat_map(|s| s.chars()).collect()
}

However, with this naive approach...

words.iter().map(|w| capitalize_first(w)).flat_map(|s| s.char_indices()).collect()

I receive these compiler errors, which I don't understand:

36   |     words.iter().map(|w| capitalize_first(w)).flat_map(|s| s.char_indices()).collect()
     |                                                                              ^^^^^^^ value of type `String` cannot be built from `std::iter::Iterator<Item=(usize, char)>`
36   |     words.iter().map(|w| capitalize_first(w)).flat_map(|s| s.char_indices()).collect()
     |     ----- ------ ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `(usize, char)` here
     |     |     |      |
     |     |     |      `Iterator::Item` changed to `String` here
     |     |     `Iterator::Item` is `&&str` here
     |     this expression has type `&[&str]`

Solution

  • Do you really need to use flat_map specifically? If not, it would be done like this:

    fn capitalize_words_strings(words: &[&str]) -> String {
        words.iter()
            .map(|word| capitalize_first(word))
            .collect()
    }
    

    If you really need to use flat_map, you can just add a "noop" flat_map by doing std::iter::once().

    fn capitalize_words_strings(words: &[&str]) -> String {
        words.iter()
            .map(|word| capitalize_first(word))
            .flat_map(|word| std::iter::once(word))
            .collect()
    }