Search code examples
rustiterator

what is "required by this bound in `map`"?


This code is from rustlings iterators2.rs

Why can't use capitalize_first as map's argument directly?

// Step 1.
// Complete the `capitalize_first` function.
// "hello" -> "Hello"
pub fn capitalize_first(input: &str) -> String {
    let mut c = input.chars();
    match c.next() {
        None => String::new(),
        Some(first) => format!("{}{}", first.to_ascii_uppercase(), &input[1..]),
    }
}

// Step 2.
// Apply the `capitalize_first` function to a slice of string slices.
// Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"]
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
    words.iter().map(capitalize_first).collect() // <-- Error
}

// 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 {
    words.iter().map(|str| capitalize_first(str)).collect()
}

Errors:

error[E0631]: type mismatch in function arguments
   --> exercises/standard_library_types/iterators2.rs:24:22
    |
11  | pub fn capitalize_first(input: &str) -> String {
    | ---------------------------------------------- found signature defined here
...
24  |     words.iter().map(capitalize_first).collect()
    |                  --- ^^^^^^^^^^^^^^^^ expected due to this
    |                  |
    |                  required by a bound introduced by this call
    |
    = note: expected function signature `fn(&&str) -> _`
               found function signature `for<'r> fn(&'r str) -> _`
note: required by a bound in `map`
   --> /Users/mattzhou/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:779:12
    |
779 |         F: FnMut(Self::Item) -> B,
    |            ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `map`
```

I don't understand what does "required by this bound in map" mean. What's the different of calling a closure or a function?


Solution

  • Read the whole error message, not just the last line.

    error[E0631]: type mismatch in function arguments
    ...
        = note: expected function signature `fn(&&str) -> _`
                   found function signature `for<'r> fn(&'r str) -> _`
    

    You are trying to use a function that accepts &str but due to the iterator type you have, the argument to the mapping function is &&str. Recall that .iter() usually borrows the value it's called on and doesn't consume it, so it iterates over &T where T is the type of item in the collection. Since T is &str, &T is &&str.

    You would have to use a lambda to dereference the nested reference, e.g.:

    words.iter().map(|&s| capitalize_first(s)).collect()
    

    Alternatively, you can use the copied() iterator function, which unwraps one level of references by copying the referent (a &str in this case, so the string data itself is not copied):

    words.iter().copied().map(capitalize_first).collect()