Search code examples
rustfunctional-programmingreferencerust-cargoborrow-checker

Rust's Reduce Method on Vec Reference


I am trying to reduce a reference of a Vec to its sum so I can calculate its mean. I am running into complier issues though and I am not following how things are not being borrowed/referenced correctly.

// Given a list of integers, use a vector and return the mean (the average value), median (when sorted, the value in the middle position), and mode (the value that occurs most often; a hash map will be helpful here) of the list.
fn main() {
    let list_of_integers = vec![200, -6_000, 3, 0, 23, 99, -1];

    let mean_ans = mean(&list_of_integers);
    // Other code that will also use list_of_integers hence why I want to reference list_of_integers so it doesn't get removed from memory

    println!("mean is {}", mean_ans);
}

fn mean(integers: &Vec<i32>) -> i32 {
    let length = integers.len() as i32;
    let sum = integers.iter().reduce(|&a, &b| &(a + b));

    match sum {
        Some(v) => v / length,
        None => 0,
    }
}

I'm receiving a complier error when I run cargo run and rust-analyzer also highlights the &(a + b) of the reduce method as wrong too. The text of the error is below but I've also attached the image to clearly show what it is referencing too.

error[E0515]: cannot return reference to temporary value
  --> src\main.rs:13:47
   |
13 |     let sum = integers.iter().reduce(|&a, &b| &(a + b));
   |                                               ^-------
   |                                               ||
   |                                               |temporary value created here
   |                                               returns a reference to data owned by the current function

error: aborting due to previous error

Error saying temporary value created here but returns a reference to data owner by the current function

I am unsure what is wrong here as I understand .iter() returns an Iter reference to the Vec so shouldn't its reduced values of a and b already be &i32? When I remove & from &(a + b), I get the following complier error "expected &i32, found i32 help: consider borrowing here: &(a + b)".

Note I am just learning Rust and I am less than halfway through its tutorial so please feel free to explain the solution as if I'm a newbie (since I am).

I am using rust version 1.52.1 with rustup version 1.24.1 on windows 10 in VSCode.


Solution

  • Returning &(a + b) doesn't work because it attempts to return a reference to a temporary value. The result of a + b behaves like an unnamed local variable, i.e. it's local to the closure and destroyed prior to its return. The most elegant way to fix the problem is to use integers.iter().copied() to obtain an iterator over actual numbers rather than references. This allows omitting & in both places.

    Note that an expression like &(a + b) is not always meaningless. It's quite useful when you pass the reference downward, say to a function or an operator that expects a reference. In that case e.g. f(&(a + b)) is shorthand for { let _tmp = a + b; f(&tmp) }, and makes perfect sense.

    Unrelated to the above, you probably want your function to accept a slice, &[i32], rather than reference to a vector. This will work with vectors unchanged and will make your function accept other contiguous slices of memory, e.g. coming from arrays. (See here for details.)