这两个片段来自 Python,在行为上几乎完全等同。它们都工作并提供相同的输出,尽管它们生成的字节码略有不同。
def lower_case(s):
return s.lower()
map(lower_case, ["A", "B"])
Run Code Online (Sandbox Code Playgroud)
与
def lower_case(s):
return s.lower()
map(lambda s: lower_case(s), ["A", "B"])
Run Code Online (Sandbox Code Playgroud)
学习 Rust,我正在尝试解决以下案例。有一个函数接收字符串并返回第一个字符大写的字符串版本:
pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + c.as_str(),
}
}
Run Code Online (Sandbox Code Playgroud)
用另一个接受字符串向量的函数包装这个函数是有趣的地方:
pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + c.as_str(),
}
}
pub fn capitalize_words(words: Vec<&str>) -> Vec<String> {
words.iter().map(|w| capitalize_first(w)).collect::<Vec<String>>()
}
Run Code Online (Sandbox Code Playgroud)
这有效,但是替换
words.iter().map(|w| capitalize_first(w)).collect::<Vec<String>>()
Run Code Online (Sandbox Code Playgroud)
和
words.iter().map(capitalize_first).collect::<Vec<String>>()
Run Code Online (Sandbox Code Playgroud)
导致编译失败并出现以下错误:
error[E0631]: type mismatch in function arguments
--> exercises/standard_library_types/iterators2.rs:27:22
|
12 | pub fn capitalize_first(input: &str) -> String {
| ---------------------------------------------- found signature of `for<'r> fn(&'r str) -> _`
...
27 | words.iter().map(capitalize_first).collect::<Vec<String>>()
| ^^^^^^^^^^^^^^^^ expected signature of `fn(&&str) -> _`
error[E0599]: no method named `collect` found for struct `std::iter::Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> std::string::String {capitalize_first}>` in the current scope
--> exercises/standard_library_types/iterators2.rs:27:40
|
27 | words.iter().map(capitalize_first).collect::<Vec<String>>()
| ^^^^^^^ method not found in `std::iter::Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> std::string::String {capitalize_first}>`
|
::: C:\Users\Adi\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\src\libcore\iter\adapters\mod.rs:809:1
|
809 | pub struct Map<I, F> {
| -------------------- doesn't satisfy `_: std::iter::Iterator`
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
`<for<'r> fn(&'r str) -> std::string::String {capitalize_first} as std::ops::FnOnce<(&&str,)>>::Output = _`
which is required by `std::iter::Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> std::string::String {capitalize_first}>: std::iter::Iterator`
`for<'r> fn(&'r str) -> std::string::String {capitalize_first}: std::ops::FnMut<(&&str,)>`
which is required by `std::iter::Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> std::string::String {capitalize_first}>: std::iter::Iterator`
`std::iter::Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> std::string::String {capitalize_first}>: std::iter::Iterator`
which is required by `&mut std::iter::Map<std::slice::Iter<'_, &str>, for<'r> fn(&'r str) -> std::string::String {capitalize_first}>: std::iter::Iterator`
Run Code Online (Sandbox Code Playgroud)
我相信我明白。
但是,按照建议进行更改
capitalize_first(input: &str)
Run Code Online (Sandbox Code Playgroud)
到
capitalize_first(input: &&str)
Run Code Online (Sandbox Code Playgroud)
通过编译,但现在测试失败(显然,因为capitalize_first是用&str,而不是调用&&str):
error[E0308]: mismatched types
--> exercises/standard_library_types/iterators2.rs:40:37
|
40 | assert_eq!(capitalize_first("hello"), "Hello");
| ^^^^^^^ expected `&str`, found `str`
|
= note: expected reference `&&str`
found reference `&'static str`
error[E0308]: mismatched types
--> exercises/standard_library_types/iterators2.rs:45:37
|
45 | assert_eq!(capitalize_first(""), "");
| ^^ expected `&str`, found `str`
|
= note: expected reference `&&str`
found reference `&'static str`
Run Code Online (Sandbox Code Playgroud)
是否有任何妥协可以允许words.iter().map(capitalize_first).collect::<Vec<String>>()工作,同时仍然允许现有测试通过capitalize_first?
map(capitalize_first)和之间的区别map(|x| capitalize_first(x))可能可以忽略不计(视觉上、语法上和性能方面),但是定义一个接受参数的闭包只是为了调用具有相同参数的函数(有些人甚至会说这是一种反模式)是非常烦人的)。
您可以更改capitalize_first为使用具有以下特征的泛型AsRef:
pub fn capitalize_first<T: AsRef<str>>(input: T) -> String {
// use .as_ref() here to convert to &str
let mut c = input.as_ref().chars();
match c.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + c.as_str(),
}
}
Run Code Online (Sandbox Code Playgroud)
这将使其与&strand &&str(以及String对 的任意数量的嵌套引用str)兼容。