i'm writing case-insensitive anagram finder given word , list of words. have following code:
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() }
the logic of sort lowercase given word, , each word in vector, same. if words different pre-sort (to eliminate self-anagrams) same post-sort, add output.
the above seems have problems capturing s
, s_sorted
surrounding scope, though, because when compile following error:
error: type mismatch: type
[closure@src/lib.rs:23:25: 32:6 s_sorted:_, s:_]
implements traitfor<'r> core::ops::fnmut<(&'r str,)>
, traitcore::ops::fnmut<(&&str,)>
required (expected &-ptr, found str)
when looked @ description of error type ([e0281]), found following tl;dr:
the issue in case
foo
defined acceptingfn
no arguments, closure attempted pass requires 1 argument.
this confusing because thought move closures capture variables surrounding scope.
what missing?
this doesn't have capturing variables in closure. let's check out error message again, reformatted bit:
type mismatch: type `[closure@<anon>:5:25: 14:6 s_sorted:_, s:_]` implements trait `for<'r> core::ops::fnmut<(&'r str,)>`, trait `core::ops::fnmut<(&&str,)>` required (expected &-ptr, found str)
and more clearly:
found: for<'r> core::ops::fnmut<(&'r str,)> expected: core::ops::fnmut<(&&str,)>
and zooming in further:
found: &'r str expected: &&str
the culprit this: |word: &str|
.
you have declared closure accepts string slice, that's not iterator yields. v
slice of &str
, , iterator on slice returns references items in slice. each iterator element &&str
.
change closure |&word|
, work. uses pattern matching dereference closure argument once before value bound word
. equivalently (but less idiomatically), use |word|
, *word
inside closure.
additionally...
you don't need restrict
'static
strings:pub fn anagrams_for<'a>(s: &str, v: &[&'a str]) -> vec<&'a str> {
it doesn't need
move
closure.- extract logic of creating vector of sorted chars. helps ensure logic stays consistent between 2 and means don't have declare vectors mutable longer needed.
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() {}
Comments
Post a Comment