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?
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()