如何在Rust中过滤自定义结构的向量?

Zel*_*ahl 10 struct filtering vector rust

我试图筛选Vec<Vocabulary>这里Vocabulary是一个自定义的struct,它本身包含一个struct VocabularyMetadataVec<Word>:

#[derive(Serialize, Deserialize)]
pub struct Vocabulary {
    pub metadata: VocabularyMetadata,
    pub words: Vec<Word>
}
Run Code Online (Sandbox Code Playgroud)

这用于处理Web应用程序中的路由,其中​​路由如下所示:/word/<vocabulary_id>/<word_id>.

这里是我当前的代码试图filterVec<Vocabulary>:

let the_vocabulary: Vec<Vocabulary> = vocabulary_context.vocabularies.iter()
    .filter(|voc| voc.metadata.identifier == vocabulary_id)
    .collect::<Vec<Vocabulary>>();
Run Code Online (Sandbox Code Playgroud)

这不起作用.我得到的错误是:

 the trait `std::iter::FromIterator<&app_structs::Vocabulary>` is not implemented for `std::vec::Vec<app_structs::Vocabulary>` [E0277]
Run Code Online (Sandbox Code Playgroud)

我不知道如何实施任何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
Run Code Online (Sandbox Code Playgroud)

所以它似乎String实现了FromIterator.

但是,我没有得到,为什么我不能简单地Vec从the filtercollect方法中获取元素.

我怎么能filter我的Vec,只是拿到的元素Vec<Vocabulary>,为此,条件是真的吗?

She*_*ter 20

学习如何创建一个最小,完整,可验证的示例非常重要的编程技巧.你的问题可以减少到这个:

struct Vocabulary;

fn main() {
    let numbers = vec![Vocabulary];
    let other_numbers: Vec<Vocabulary> = numbers.iter().collect();
}
Run Code Online (Sandbox Code Playgroud)

让我们看一下您案例的错误消息:

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>`
Run Code Online (Sandbox Code Playgroud)

这说明a Vec<Vocabulary>不能从迭代器构建&Vocabulary.你看得到差别吗?你有一个references(&)的迭代器,而不是值的迭代器.如何Vec知道如何将引用转换为值?


你是如何解决的?我不知道在你的情况下哪种方法最有效:

  1. 不要迭代引用,迭代值本身.这要求您拥有向量的所有权.使用into_iter而不是iter:

    let the_vocabulary: Vec<Vocabulary> = vocabulary_context
        .vocabularies
        .into_iter()
        .filter(|voc| voc.metadata.identifier == vocabulary_id)
        .collect();
    
    Run Code Online (Sandbox Code Playgroud)
  2. 通过克隆它们来复制对象.这需要您在实现上迭代的类型Clone.如果您将此与过滤配对,则应cloned()在过滤之后和调用之前调用collect()以避免克隆您丢弃的内容.

    let the_vocabulary: Vec<Vocabulary> = vocabulary_context
        .vocabularies
        .drain(..)
        .filter(|voc| voc.metadata.identifier == vocabulary_id)
        .collect();
    
    Run Code Online (Sandbox Code Playgroud)
  3. 不收集价值,收集Vec参考资料.这要求您使用之后的项目可以通过引用而不是值来获取项目:

    let the_vocabulary: Vec<Vocabulary> = vocabulary_context
        .vocabularies
        .iter()
        .filter(|voc| voc.metadata.identifier == vocabulary_id)
        .cloned()
        .collect();
    
    Run Code Online (Sandbox Code Playgroud)

请注意,我删除了冗余类型说明符(turbofish ::<>on collect).您只需指定变量的类型或on collect,而不是两者.实际上,所有三个示例都可以从let the_vocabulary: Vec<_>让编译器基于迭代器推断集合内的类型开始.这是惯用的风格,但我保留了明确的类型用于演示目的.


也可以看看: