What's the difference between filter(|x|) and filter(|&x|)?

416 views Asked by At

In the Rust Book there is an example of calling filter() on an iterator:

for i in (1..100).filter(|&x| x % 2 == 0) {
    println!("{}", i);
}

There is an explanation below but I'm having trouble understanding it:

This will print all of the even numbers between one and a hundred. (Note that because filter doesn't consume the elements that are being iterated over, it is passed a reference to each element, and thus the filter predicate uses the &x pattern to extract the integer itself.)

This, however does not work:

for i in (1..100).filter(|&x| *x % 2 == 0) {
    println!("i={}", i);
}

Why is the argument to the closure a reference |&x|, instead of |x|? And what's the difference between using |&x| and |x|?

I understand that using a reference |&x| is more efficient, but I'm puzzled by the fact that I didn't have to dereference the x pointer by using *x.

1

There are 1 answers

2
Shepmaster On BEST ANSWER

When used as a pattern match (and closure and function arguments are also pattern matches), the & binds to a reference, making the variable the dereferenced value.

fn main() {
    let an_int: u8 = 42;
    // Note that the `&` is on the right side of the `:`
    let ref_to_int: &u8 = &an_int; 
    // Note that the `&` is on the left side of the `:`
    let &another_int = ref_to_int;
    let () = another_int;
}

Has the error:

error: mismatched types:
 expected `u8`,
    found `()`

If you look at your error message for your case, it indicates that you can't dereference it, because it isn't a reference:

error: type `_` cannot be dereferenced

I didn't have to dereference the x pointer by using *x.

That's because you implicitly dereferenced it in the pattern match.

I understand that using a reference |&x| is more efficient

If this were true, then there would be no reason to use anything but references! Namely, references require extra indirection to get to the real data. There's some measurable cut-off point where passing items by value is more efficient than passing references to them.

If so, why does using |x| not throw an error? From my experience with C, I would expect to receive a pointer here.

And you do, in the form of a reference. x is a reference to (in this example) an i32. However, the % operator is provided by the trait Rem, which is implemented for all pairs of reference / value:

impl Rem<i32> for i32
impl<'a> Rem<i32> for &'a i32
impl<'a> Rem<&'a i32> for i32
impl<'a, 'b> Rem<&'a i32> for &'b i32

This allows you to not need to explicitly dereference it.

Or does Rust implicitly allocate a copy of value of the original x on the stack here?

It emphatically does not do that. In fact, it would be unsafe to do that, unless the iterated items implemented Copy (or potentially Clone, in which case it could also be expensive). This is why references are used as the closure argument.