Why iterable filter expose double reference?

Hello !

I'm wondering why :

let numbers = vec![0, 2, 3, 4, 5, 6, 7, 8, 9];
let new_numbers = numbers.iter().filter(|v| v > &2);

Is not valid :

error[E0308]: mismatched types
 --> src/main.rs:4:53
  |
4 |     let new_numbers = numbers.iter().filter(|v| v > &2);
  |                                                     ^^ expected reference, found integer
  |
  = note: expected reference `&&_`
             found reference `&{integer}`

Why v is double reference ? I have no choice than to write .filter(|v| v > &&2) ?

Thanks !

.iter() gives you references in the first place. But .filter() has to give another layer of references in order to work with all types, because if it didn't, it would consume the iterator's elements – which would make it impossible for those elements to be returned if the item type wasn't Clone or Copy.

By the way, this exact scenario is addressed in the documentation. You should read the documentation of APIs you are using. (But it could have been deduced from the type signatures as well.)

I have no choice than to write .filter(|v| v > &&2) ?

I would be more idiomatic to write .filter(|&&v| v > 2) for a primitive type that is Copy.

3 Likes

This is because iterator code is generic, designed to also work on types that cannot be copied. And Rust doesn't automatically flatten references, except some magic around the . operator.

Alternatives:

filter(|&&v| v > 2);

Moving && to the pattern in closure arguments removes the reference and gives you just the value


numbers.iter().copied()

This gives you i32 instead of &i32.

1 Like

Thanks !

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.