私はVec<Vocabulary>
をフィルタリングしようとしています。ここで、Vocabulary
はカスタムstruct
であり、それ自体にstruct
VocabularyMetadata
とVec<Word>
が含まれています。
#[derive(Serialize, Deserialize)]
pub struct Vocabulary {
pub metadata: VocabularyMetadata,
pub words: Vec<Word>
}
これはWebアプリケーションでルートを処理するためのもので、ルートは次のようになります:/Word/<vocabulary_id>/<Word_id>
。
Vec<Vocabulary>
をfilter
しようとしている現在のコードは次のとおりです。
let the_vocabulary: Vec<Vocabulary> = vocabulary_context.vocabularies.iter()
.filter(|voc| voc.metadata.identifier == vocabulary_id)
.collect::<Vec<Vocabulary>>();
これは動作しません。私が得るエラーは:
the trait `std::iter::FromIterator<&app_structs::Vocabulary>` is not implemented for `std::vec::Vec<app_structs::Vocabulary>` [E0277]
FromIterator
を実装する方法も、なぜそれが必要になるのかもわかりません。同じWebアプリの別のルートで、同じファイルを次のように実行します。
let result: Vec<String> = vocabulary_context.vocabularies.iter()
.filter(|voc| voc.metadata.identifier.as_str().contains(vocabulary_id))
.map(encode_to_string)
.collect::<Vec<String>>();
result.join("\n\n") // returning
したがって、String
はFromIterator
を実装しているようです。
ただし、取得できません。Vec
またはfilter
メソッドからcollect
の要素を単純に取得できないのはなぜですか。
filter
my Vec
を使用して、条件がtrueであるVec<Vocabulary>
の要素を取得するにはどうすればよいですか?
最小限の再現可能な例 の作成方法を学ぶことは、非常に重要なプログラミングスキルです。あなたの問題はこれに減らすことができます:
_struct Vocabulary;
fn main() {
let numbers = vec![Vocabulary];
let other_numbers: Vec<Vocabulary> = numbers.iter().collect();
}
_
あなたのケースのエラーメッセージを見てみましょう:
_error[E0277]: a collection of type `std::vec::Vec<Vocabulary>` cannot be built from an iterator over elements of type `&Vocabulary` --> src/main.rs:5:57 | 5 | let other_numbers: Vec<Vocabulary> = numbers.iter().collect(); | ^^^^^^^ a collection of type `std::vec::Vec<Vocabulary>` cannot be built from `std::iter::Iterator<Item=&Vocabulary>` | = help: the trait `std::iter::FromIterator<&Vocabulary>` is not implemented for `std::vec::Vec<Vocabulary>`
_
これは、_Vec<Vocabulary>
_を_&Vocabulary
_のイテレータから構築できないことを示しています。違いがわかりますか?参照のイテレータ(_&
_)、not値のイテレータがあります。参照を値に変換する方法をVec
はどのように知っていますか?
どのように修正しますか?私はあなたの状況で何が最もうまくいくかわかりません:
参照を反復するのではなく、値自体を反復します。デフォルトの選択では、ベクターの所有権が必要です。 iter
の代わりに_into_iter
_を使用:
_let the_vocabulary: Vec<Vocabulary> = vocabulary_context
.vocabularies
.into_iter()
.filter(|voc| voc.metadata.identifier == vocabulary_id)
.collect();
_
変更可能な参照がある場合は、イテレータをdrainすることもできます。
_let the_vocabulary: Vec<Vocabulary> = vocabulary_context
.vocabularies
.drain(..)
.filter(|voc| voc.metadata.identifier == vocabulary_id)
.collect();
_
オブジェクトを複製してオブジェクトを複製します。これには、反復する型がClone
を実装する必要があります。これとフィルタリングを組み合わせる場合は、フィルタリングした後、cloned()
を呼び出す前にcollect()
を呼び出して、破棄するものを複製しないようにする必要があります。
_let the_vocabulary: Vec<Vocabulary> = vocabulary_context
.vocabularies
.iter()
.filter(|voc| voc.metadata.identifier == vocabulary_id)
.cloned()
.collect();
_
値を収集せず、Vec
の参照を収集します。ただし、後でアイテムを使用する場合は、値ではなく参照でアイテムを取得できます。
_let the_vocabulary: Vec<&Vocabulary> = vocabulary_context
.vocabularies
.iter()
.filter(|voc| voc.metadata.identifier == vocabulary_id)
.collect();
_
冗長な型指定子(collect
のturbofish _::<>
_)を削除したことに注意してください。変数のタイプまたはcollect
の両方を指定する必要はありません。実際、3つの例はすべて_let the_vocabulary: Vec<_>
_で始まり、コンパイラーがイテレーターに基づいてコレクション内の型を推測できるようにすることができます。これは慣用的なスタイルですが、デモのために明示的なタイプを保持しました。
以下も参照してください。