`.map(f)`和`.map(xf(x))`之间有什么区别?

在做rustlings 时standard_library_types/iterators2.rs,我开始想知道如何std::iter::Iterator::map调用它的参数闭包/函数。更具体地说,假设我有一个功能

// "hello" -> "Hello"
pub fn capitalize_first(input: &str) -> String {
    let mut c = input.chars();
    match c.next() {
        None => String::new(),
        Some(first) => String::from(first.to_ascii_uppercase()) + c.as_str(),
    }
}

现在我想用它

// 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.into_iter().map(capitalize_first).collect()
}

哪个不编译

error[E0631]: type mismatch in function arguments
  --> exercises/standard_library_types/iterators2.rs:24:27
   |
11 | pub fn capitalize_first(input: &str) -> String {
   | ---------------------------------------------- found signature of `for<'r> fn(&'r str) -> _`
...
24 |     words.into_iter().map(capitalize_first).collect()
   |                           ^^^^^^^^^^^^^^^^ expected signature of `fn(&&str) -> _`

error[E0599]: the method `collect` exists for struct `Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> String {capitalize_first}>`, but its trait bounds were not satisfied
  --> exercises/standard_library_types/iterators2.rs:24:45
   |
24 |       words.into_iter().map(capitalize_first).collect()
   |                                               ^^^^^^^ method cannot be called on `Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> String {capitalize_first}>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `<for<'r> fn(&'r str) -> String {capitalize_first} as FnOnce<(&&str,)>>::Output = _`
           which is required by `Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> String {capitalize_first}>: Iterator`
           `for<'r> fn(&'r str) -> String {capitalize_first}: FnMut<(&&str,)>`
           which is required by `Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> String {capitalize_first}>: Iterator`
           `Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> String {capitalize_first}>: Iterator`
           which is required by `&mut Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> String {capitalize_first}>: Iterator`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0599, E0631.
For more information about an error, try `rustc --explain E0599`.

但是,在我更改.map(capitalize_first).map(|x| capitalize_first(x)). 显然,Rust 在将每个项目传递给 的参数闭包/函数之前借用(不确定是可变还是不可变)map,这是有道理的,因为我们通常不想消耗被迭代的对象。

我无法理解的是,为什么 Rust 不借用|x| capitalize_first(x). 我假设闭包|x| capitalize_first(x)仍然得到&&str,然后自动取消引用规则启动并将其取消引用到&str,但这并不能解释为什么在我使用函数时它没有启动capitalize_first。什么之间的区别.map(|x| capitalize_first(x)).map(capitalize_first)?考虑到参数map是一个 trait 对象,这里是否发生了动态调度?

注意:这个问题与使用带有 iter().map() 的函数不同 - 作为命名函数 vs 作为闭包,因为我问的是为什么,而另一篇文章问的是如何。关于该问题的公认答案,如果有人能解释为什么我们需要AsRef而 Rust 已经具有自动取消引用规则,我将不胜感激。

回答

为什么我可以capitalize_first&&str参数调用?

自动取消引用规则的链接问答专门针对self使用a.b()语法时如何解决。参数规则一般跳过自动引用步骤,只依赖Deref coercions。由于&&str实现Deref<Target = &str>(实际上所有引用都实现了Deref),这个&&str->&str转换透明地发生。

为什么它不工作.map()呢?

简单明了,map()就是期待实现Fn(&&str) -> Tcapitalize_first没有实现的东西。AFn(&str)不是透明地转换为 a Fn(&&str),它需要一个像闭包引入的转换步骤(尽管是透明的)。


以上是`.map(f)`和`.map(xf(x))`之间有什么区别?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>