1
votes

I was reading the chapter on higher order functions of Rust by Example. Where they present the following canonical example:

fn is_odd(n: u32) -> bool {
    n % 2 == 1
}

fn main() {
   let upper = 1000;

   println!("imperative style: {}", acc);

   let sum_of_squared_odd_numbers: u32 =
       (0..).map(|n| n * n)                             // All natural numbers squared
            .take_while(|&n_squared| n_squared < upper) // Below upper limit
            .filter(|&n_squared| is_odd(n_squared))     // That are odd
            .fold(0, |acc, n_squared| acc + n_squared); // Sum them
}

Simple enough. But I realized that I don't understand the type of parameter n_squared. Both take_while and filter accept a function that takes a parameter by reference. That makes sense to me, you want to borrow instead of consuming the values in the map.

However, if n_squared is a reference, why don't I have to dereference it before comparing its value to limit or equally surprising; why can I pass it directly to is_odd() without dereferencing?

I.e. why isn't it?

   |&n_squared| *n_squared < upper

When I try that the compiler gives the following error:

error[E0614]: type `{integer}` cannot be dereferenced
  --> src\higherorder.rs:13:34
   |
13 |         .take_while(|&n_squared| *n_squared <= upper)
   |      

Indicating that n_squared is an i32 and not &i32. Looks like some sort pattern matching/destructuring is happening here, but I was unable to find the relevant documentation.

1
If you write |n_squared|, you'll get the expected error and using *n_squared in the body will fix it. See reddit.com/r/rust/comments/16b9wh/…Alexey Romanov
Since I edited the comment and you might not have seen it: I've added a link to an old Reddit discussion of exactly this issue reddit.com/r/rust/comments/16b9wh/…. While Rust has changed a lot, this seems to still be what's going happening.Alexey Romanov
@AlexeyRomanov Perfect! That's what I was looking for.djf

1 Answers

5
votes

You are using function parameter destructuring:

|&n_squared| n_squared < upper

is functionally equivalent to:

|n_squared| *n_squared < upper

To understand this better, imagine you're passing a tuple of type &(i32, i32) to a lambda:

|&(x, y) : &(i32, i32)| x + y