Reputation: 38733
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?
Upvotes: 3
Views: 7353
Reputation: 2243
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 == &¤t_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 == ¤t_word_id)
.collect();
}
Upvotes: 9
Reputation: 33370
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>>();
Upvotes: 2