2016-03-26 8 views
1

私は大文字と小文字を区別しないアナグラムファインダを書いています。私は次のコードを持っています:Rustのクロージャの範囲外の変数をキャプチャするにはどうすればよいですか?

この論理は、指定された小文字のソートを行い、ベクトル内の各単語について同じことを行います。単語が異なるプレ・ソート(自己アナグラムを除く)で、同じポスト・ソートの場合は、出力に追加します。 [Iこのエラータイプ(の説明を見たとき

error: type mismatch: the type [[email protected]/lib.rs:23:25: 32: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)

上記の問題私はコンパイルするとき、私は次のエラーを取得するため、しかし、周囲の範囲からss_sortedをキャプチャを有すると思われますE0281])、私は、次のTLを発見; DR:

The issue in this case is that foo is defined as accepting a Fn with no arguments, but the closure we attempted to pass to it requires one argument.

Iが周囲範囲からmove closures capture variablesを考えこれは紛らわしいです。

私には何が欠けていますか?

答えて

3

これはクロージャの変数をキャプチャすることとは関係ありません。さんが再びエラーメッセージをチェックしてみましょう、ビットを再フォーマット:

type mismatch: 
    the type `[[email protected]<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文字列に自分自身を制限する必要はありません

  1. pub fn anagrams_for<'a>(s: &str, v: &[&'a str]) -> Vec<&'a str> { 
    
  2. それは、move閉鎖する必要はありません。

  3. ソートされた文字のベクトルを作成するロジックを抽出します。これにより、ロジックが2つのの間で一貫した状態を維持できるようになり、必要以上に長い間それらのベクトルを変更可能と宣言する必要がなくなります。
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() {} 
+0

のクローンを作成することです。移動クロージャーを使用し続けるか、(クロージャー・パラメーターのタイプを変更してイテレーターをクローンする)他のアンサーを使用する方が良いと思いますか? – erip

+2

イテレータを複製するよりも@erip * * - それは複製されるイテレータ全体ではありません。それは生成されるごとに各要素を複製する追加のアダプタです。私の希望と直感は、2つのソリューションが同等に機能しているということです。 **私はこの解決法がこの場合より慣用的であると信じている。とにかく 'move'クロージャは必要ありません(私は更新しました)。 – Shepmaster

+0

ヒントをありがとう。非常に有用で包括的。 – erip

3

ここでの問題は、あなたが&&'static strのシーケンスからVec<&'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シーケンスのポインタと長さにすぎないため、これは安価な操作です。

編集:実際にはより良い解決策は、私はword` `への参照を取ることによって、これはイテレータをクローニングよりもはるかに高速になると思われるように遅く

できるだけ
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() 
+0

それはかなりばかげていました。編集のために 'クローン'呼び出しが必要な理由を追加してもよろしいですか? – erip

関連する問題