How do I capture variables outside the scope of a closure in Rust? -


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 trait for<'r> core::ops::fnmut<(&'r str,)>, trait core::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 accepting fn 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...

  1. you don't need restrict 'static strings:

    pub fn anagrams_for<'a>(s: &str, v: &[&'a str]) -> vec<&'a str> { 
  2. it doesn't need move closure.

  3. 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