简体   繁体   中英

how to implement a filter with vec in rust

I have a vec i64 that store some element with some entity ids. I want to filter some specify entity id and return a new vec. what I am trying to implement this operation like this way in rust(this is a minimal example, the real element was some word Object):

fn main() {
    let current_word_id:i64 =1;
    let wordIds:Vec<i64> = Vec::new();;
    let current_sentences: Vec<i64> = wordIds
        .iter()
        .filter(|sen| sen == current_word_id)
        .collect();
}

when I compile this code,facing a problem like this:

error[E0277]: can't compare `&&i64` with `i64`
  --> src/main.rs:16:27
   |
16 |         .filter(|sen| sen == current_word_id)
   |                           ^^ no implementation for `&&i64 == i64`
   |
   = help: the trait `PartialEq<i64>` is not implemented for `&&i64`

error[E0277]: a value of type `Vec<i64>` cannot be built from an iterator over elements of type `&i64`
  --> src/main.rs:17:10
   |
17 |         .collect();
   |          ^^^^^^^ value of type `Vec<i64>` cannot be built from `std::iter::Iterator<Item=&i64>`
   |
   = help: the trait `FromIterator<&i64>` is not implemented for `Vec<i64>`

Some errors have detailed explanations: E0277, E0432.
For more information about an error, try `rustc --explain E0277`.

I am follow the https://codereview.stackexchange.com/questions/244880/filtering-a-vec-of-structs-and-creating-new-vector-of-strings-or-strs-in-rust . why did not work as expect? What should I do to make it work? what is the right way to do some filter with vec in rust?

So... there's a few things here.

When iterating over Vec , there are 2 methods you can use - iter(&self) and into_iter(self) . The first takes a reference to the Vec and iterates over that - essentially a view into the Vec . The second consumes the Vec and iterates over that, destroying it in the process and turning the Vec into an iterator.

You have used the first, therefore you shall be dealing with references inside the Vec<i64> or &i64 . The filter function should not take the values iterated over because that would mean draining the iterator, so it takes a reference to the elements inside the iterators (in this case &i64 thus getting a &&i64 ). So fixing the &&i64 == i64 issue is down to just making sure the types match (ie. |sen| sen == &&current_word_id or dereferencing the sen ).

The second part here is that because you are iterating over &i64 as we saw before, this is exactly what you would collect. This can be fixed by mapping the items to a dereferenced value. Given that this is also a possibility in the first problem, this mapping can happen before the filter.

Putting it together, it would bring the example down to this:

fn main() {
    let current_word_id:i64 =1;
    let wordIds:Vec<i64> = Vec::new();
    let current_sentences: Vec<i64> = wordIds
        .iter()
        .map(|v| *v)
        .filter(|sen| sen == &current_word_id)
        .collect();
}

From the documentation , you'll see they point out why this is:

Because the closure passed to filter() takes a reference, and many iterators iterate over references, this leads to a possibly confusing situation, where the type of the closure is a double reference:

You'll want something like this:

wordIds.iter().filter(|sen| **sen == current_word_id).collect::<Vec<&i64>>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM