我正在尝试过滤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>
。
以下是我当前的代码filter
Vec<Vocabulary>
:
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
我的Vec
并简单地获取条件为真的Vec<Vocabulary>
元素?
答案 0 :(得分:17)
非常重要的编程技巧,了解如何创建minimal, complete, verifiable example。您的问题可以简化为:
fn main() {
let numbers = vec![1i32];
let other_numbers: Vec<i32> = numbers.iter().collect();
}
让我们看一下您案例的错误消息:
error[E0277]: the trait bound `std::vec::Vec<i32>: std::iter::FromIterator<&i32>` is not satisfied --> src/main.rs:3:50 | 3 | let other_numbers: Vec<i32> = numbers.iter().collect(); | ^^^^^^^ a collection of type `std::vec::Vec<i32>` cannot be built from an iterator over elements of type `&i32` | = help: the trait `std::iter::FromIterator<&i32>` is not implemented for `std::vec::Vec<i32>`
这表示无法从Vec<Vocabulary>
的迭代器构建&Vocabulary
。你看得到差别吗?你有一个引用的迭代器(&
),不是值的迭代器。 Vec
如何知道如何将引用转换为值?
你是如何解决的?我不知道在你的情况下哪种方法最有效:
不要遍历引用,迭代值本身。这要求您拥有向量的所有权。使用into_iter
代替iter
:
let the_vocabulary: Vec<Vocabulary> = vocabulary_context
.vocabularies
.into_iter()
.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();
请注意,我删除了冗余类型说明符(::<>
上的turbofish collect
)。您只需要指定变量的类型或collect
,而不是两者。实际上,所有三个示例都可以从let the_vocabulary: Vec<_>
开始,让编译器根据迭代器推断集合中的类型。这是惯用的风格,但为了演示目的,我保留了明确的类型。
另见: