我正在写一个不区分大小写的anagram finder,给出一个单词和一个单词列表。我有以下代码:
pub fn anagrams_for(s: &'static str, v: &[&'static str]) -> Vec<&'static str> {
let mut s_sorted: Vec<_> = s.to_lowercase().chars().collect();
s_sorted.sort();
v.iter().filter_map(move |word: &str| {
let mut word_sorted: Vec<_> = word.to_lowercase().chars().collect();
word_sorted.sort();
if word_sorted == s_sorted && s.to_lowercase() != word.to_lowercase() {
Some(word)
} else {
None
}
}).collect()
}
这样做的逻辑是对给定单词的小写进行排序,对于向量中的每个单词,执行相同的操作。如果单词预先排序不同(消除自我字谜)但是后排序相同,则将其添加到输出中。
上述似乎在从周围范围捕获s
和s_sorted
时遇到问题,因为在编译时我收到以下错误:
错误:类型不匹配:类型
[closure@src/lib.rs:23:25: 32:6 s_sorted:_, s:_]
实现了特征for<'r> core::ops::FnMut<(&'r str,)>
,但特征core::ops::FnMut<(&&str,)>
是必需的(预期&amp; -ptr,找到str)
当我查看此错误类型的描述([E0281])时,我发现了以下TL; DR:
在这种情况下的问题是
foo
被定义为接受Fn
而没有 参数,但我们试图传递给它的闭包需要一个参数。
这令人困惑,因为我认为来自周围范围的move closures capture variables。
我错过了什么?
答案 0 :(得分:3)
这与在闭包中捕获变量没有任何关系。让我们再次查看错误消息,重新格式化一下:
type mismatch:
the type `[closure@<anon>:5:25: 14:6 s_sorted:_, s:_]`
implements the trait `for<'r> core::ops::FnMut<(&'r str,)>`,
but the trait `core::ops::FnMut<(&&str,)>` is required
(expected &-ptr, found str)
更清楚的是:
found: for<'r> core::ops::FnMut<(&'r str,)>
expected: core::ops::FnMut<(&&str,)>
进一步放大:
found: &'r str
expected: &&str
罪魁祸首是:|word: &str|
。
您已声明您的闭包接受字符串切片,但不是迭代器产生的。 v
是&str
的切片,切片上的迭代器返回对切片中项目的引用。每个迭代器元素都是&&str
。
将关闭更改为|&word|
,它会起作用。在值绑定到word
之前,这使用模式匹配来取消引用闭包参数。等价(但不太惯用),您可以在闭包内使用|word|
然后*word
。
此外...
您不需要将自己限制在'static
字符串:
pub fn anagrams_for<'a>(s: &str, v: &[&'a str]) -> Vec<&'a str> {
不需要move
关闭。
fn sorted_chars(s: &str) -> Vec<char> {
let mut s_sorted: Vec<_> = s.to_lowercase().chars().collect();
s_sorted.sort();
s_sorted
}
pub fn anagrams_for<'a>(s: &str, v: &[&'a str]) -> Vec<&'a str> {
let s_sorted = sorted_chars(s);
v.iter().filter_map(|&word| {
let word_sorted = sorted_chars(word);
if word_sorted == s_sorted && s.to_lowercase() != word.to_lowercase() {
Some(word)
} else {
None
}
}).collect()
}
fn main() {}
答案 1 :(得分:3)
此处的问题是您尝试从Vec<&'static str>
的序列中创建&&'static str
。
pub fn anagrams_for(s: &'static str, v: &[&'static str]) -> Vec<&'static str> {
let mut s_sorted: Vec<_> = s.to_lowercase().chars().collect();
s_sorted.sort();
v.iter().cloned().filter_map(|word: &'static str| {
let mut word_sorted: Vec<_> = word.to_lowercase().chars().collect();
word_sorted.sort();
if word_sorted == s_sorted && s.to_lowercase() != word.to_lowercase() {
Some(word)
} else {
None
}
}).collect()
}
从cloned
到&&'static str
,&'static str
来电是必要的。这是一个廉价的操作,因为&str
只是指向某个utf8序列的指针,加上一个长度。
编辑:实际上更好的解决方案是尽可能晚地克隆
v.iter().filter_map(move |word: &&'static str| { // <--- adapted the type to what is actually received
let mut word_sorted: Vec<_> = word.to_lowercase().chars().collect();
word_sorted.sort();
if word_sorted == s_sorted && s.to_lowercase() != word.to_lowercase() {
Some(word.clone()) // <--- moved clone operation here
} else {
None
}
}).collect()