`.map(f)` 和 `.map(|x| f(x))` 有什么区别?
What's the differenece between `.map(f)` and `.map(|x| f(x))`?
在执行 rustlings standard_library_types/iterators2.rs
, I started wondering how std::iter::Iterator::map
时调用其参数 closure/function。更具体地说,假设我有一个函数
// "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
的参数 closure/function 之前借用(不确定可变或不可变)每个项目,这是有道理的,因为我们通常不想消耗被迭代的对象。
我无法理解的是为什么 Rust 不借用 |x| capitalize_first(x)
的参数。我假设闭包 |x| capitalize_first(x)
仍然得到 &&str
,然后 启动并将其取消引用到 &str
,但这并不能解释为什么它没有启动在我使用函数 capitalize_first
时。 .map(|x| capitalize_first(x))
和 .map(capitalize_first)
有什么区别?考虑到 map
的参数是特征对象,这里是否发生动态调度?
注意: 这个问题与 因为我问的是为什么,而另一个post问的是如何。关于这个问题的公认答案,如果有人能解释为什么我们需要 AsRef
而 Rust 已经有 .
,我将不胜感激
为什么我可以用 &&str
参数调用 capitalize_first
?
is specifically for how self
is resolved when using the a.b()
syntax. The rules for arguments in general skip the auto-reference step and just rely on Deref coercions 的链接问答。由于 &&str
实现了 Deref<Target = &str>
(实际上 all 引用实现了 Deref
),这个 &&str
-> &str
转换发生了透明地。
为什么它对 .map()
不起作用?
简单明了,map()
期望实现 Fn(&&str) -> T
而 capitalize_first
没有。 Fn(&str)
不会透明地转换为 Fn(&&str)
,它需要一个类似于闭包引入的转换步骤(尽管是透明的)。
@kmdreko 是正确的,问题在于取消引用强制。请记住,&[T]
实现 IntoIterator
,Self::Item
为 &T
。因此,如果 x : &[T]
,则 x.into_iter()
将实现 Iterator
,其中 Self::Item
为 &T
。
在你的例子中,words.into_iter()
是 Iterator
,Self::Item
是 &&str
。
map
方法需要一个域为 Self::Item
的函数。 words.into_iter().map(f)
期望 f
是一个输入类型为 &&str
的函数。
这会产生一个问题,因为 capitalize_first
的输入是 &str
,而不是 &&str
。因此,words.into_iter().map(capitalize_first)
无法键入检查。
然而,当我们查看 words.into_iter().map(|x| capitalize_first(x))
时,神奇的事情发生了。闭包 |x| capitalize_first(x)
被神奇地强制转换为 |x| capitalize_first(*x)
。然后进行类型检查。
在执行 rustlings standard_library_types/iterators2.rs
, I started wondering how std::iter::Iterator::map
时调用其参数 closure/function。更具体地说,假设我有一个函数
// "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
的参数 closure/function 之前借用(不确定可变或不可变)每个项目,这是有道理的,因为我们通常不想消耗被迭代的对象。
我无法理解的是为什么 Rust 不借用 |x| capitalize_first(x)
的参数。我假设闭包 |x| capitalize_first(x)
仍然得到 &&str
,然后 &str
,但这并不能解释为什么它没有启动在我使用函数 capitalize_first
时。 .map(|x| capitalize_first(x))
和 .map(capitalize_first)
有什么区别?考虑到 map
的参数是特征对象,这里是否发生动态调度?
注意: 这个问题与 AsRef
而 Rust 已经有
为什么我可以用 &&str
参数调用 capitalize_first
?
self
is resolved when using the a.b()
syntax. The rules for arguments in general skip the auto-reference step and just rely on Deref coercions 的链接问答。由于 &&str
实现了 Deref<Target = &str>
(实际上 all 引用实现了 Deref
),这个 &&str
-> &str
转换发生了透明地。
为什么它对 .map()
不起作用?
简单明了,map()
期望实现 Fn(&&str) -> T
而 capitalize_first
没有。 Fn(&str)
不会透明地转换为 Fn(&&str)
,它需要一个类似于闭包引入的转换步骤(尽管是透明的)。
@kmdreko 是正确的,问题在于取消引用强制。请记住,&[T]
实现 IntoIterator
,Self::Item
为 &T
。因此,如果 x : &[T]
,则 x.into_iter()
将实现 Iterator
,其中 Self::Item
为 &T
。
在你的例子中,words.into_iter()
是 Iterator
,Self::Item
是 &&str
。
map
方法需要一个域为 Self::Item
的函数。 words.into_iter().map(f)
期望 f
是一个输入类型为 &&str
的函数。
这会产生一个问题,因为 capitalize_first
的输入是 &str
,而不是 &&str
。因此,words.into_iter().map(capitalize_first)
无法键入检查。
然而,当我们查看 words.into_iter().map(|x| capitalize_first(x))
时,神奇的事情发生了。闭包 |x| capitalize_first(x)
被神奇地强制转换为 |x| capitalize_first(*x)
。然后进行类型检查。