Iterating a HashMap and filtering has double reference type

Here are pieces of my code:

// struct from osmpbfreader
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Copy, Serialize, Deserialize)]
pub struct NodeId(pub i64);

type WaysInNodesCounter = HashMap<NodeId, i32>;
...
let vertice = counter.iter().filter(|(n, v)| v != 2).map(|(k, v)| k).collect();

Getting an error:

error: src/main.rs:35: can't compare `&&i32` with `{integer}`
error: src/main.rs:35: no implementation for `&&i32 == {integer}`
help: src/main.rs:35: the trait `PartialEq<{integer}>` is not implemented for `&&i32`

I corrected it by using double start:

let vertice:Vec<NodeId> = counter.iter().filter(|(n, v)| **v != 2).map(|(k, v)| *k).collect();

Is this ok, or I've done something wrong?

If I'm not going to use counter anymore, is there a way to take ownership of data in it? into_iter is not implemented for HashMap.

Yes it is. Scenarios like this are specifically mentioned in the documentation of filter().

It is.

4 Likes

I think it's also okay to borrow on the other side, e.g. &2 == &2 would be true. Or in your example: *v == &2. (Not sure if that's more idiomatic though, I think your way is better, at least as long as you're working with integers which are Copy.) That works because if T implements Eq, then &T does as well. See the implementation of PartialEq<&'_ B> for &'_ A where … A: PartialEq<B> + …, .

I find that quite noteworthy, as these things make things easier in many cases (you can just compare two references the same way you compare the values being referenced), but it can surprise you sometimes, e.g. when you attempt to compare an &i32 with an i32, which doesn't work. And then suddenly you have to work with * or & while in your previous experiences, Rust's sugar kept you from having to do that.

When I learned Rust, it was so easy (maybe a bit too easy) to forget about when you deal with the values and when with references (or references to references). But at some point, I had to pay more attention to when I pass references and when I pass values. It's not so difficult for me now, but at first it did confuse me, because in C you have to always care about whether you have a value or a pointer to it. Rust helps you sometimes – and that can make it more surprising when it doesn't.

1 Like

If you can't use into_iter it sometimes makes sense to instead use copied.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.