How do I sum a vector using fold?

VectorRust

Vector Problem Overview


This Rust tutorial explains the fold() mechanism well, and this example code:

let sum = (1..4).fold(0, |sum, x| sum + x);

works as expected.

I'd like to run it on a vector, so based on that example, first I wrote this:

let sum: u32 = vec![1,2,3,4,5,6].iter().fold(0, |sum, val| sum += val);

which threw an error:

error: binary assignment operation `+=` cannot be applied to types `_` and `&u32` [E0368]
let sum = ratings.values().fold(0, |sum, val| sum += val);
                                              ^~~~~~~~~~

I guessed this might be a reference-related error for some reason, so I changed that to fold(0, |sum, &val| sum += val), which resulted in

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

Hm, maybe something's wrong with the closure? Using {sum += x; sum }, I got

binary assignment operation `+=` cannot be applied to types `_` and `&u32`

again.

After further trial and error, adding mut to sum worked:

let sum = vec![1,2,3,4,5,6].iter().fold(0, |mut sum, &x| {sum += x; sum});

Could someone explain the reason why fold() for vectors differs so much from the tutorial? Or is there a better way to handle this?

For reference, I'm using Rust beta, 2015-04-02.

Vector Solutions


Solution 1 - Vector

Since Rust 1.11, you can sum the iterator directly, skipping fold:

let sum: u32 = vec![1, 2, 3, 4, 5, 6].iter().sum();

You've already figured out that += is the problem, but I'd like to provide some more exposition.

In your case, the arguments provided to the fold closure are _ and &u32. The first type is an not-yet-specified integer. If you change your fold call to fold(0u32, |sum, val| sum += val), you'll get a slightly different message:

let sum: u32 = vec![1,2,3,4,5,6].iter().fold(0u32, |sum, val| sum += val);

error[E0308]: mismatched types
  |
2 |     let sum: u32 = vec![1,2,3,4,5,6].iter().fold(0u32, |sum, val| sum += val);
  |                                                                          ^^^ expected u32, found &{integer}
  |
  = note: expected type `u32`
  = note:    found type `&{integer}`

The result value of the binary assignment operation += is (), the unit type. This explains the error message when you changed to fold(0, |sum, &val| sum += val):

let mut a = 1;
let what_am_i = a += 1;
println!("{:?}", what_am_i); // => ()

If you change to fold(0, |sum, &val| {sum += val ; sum}), you then get an understandable error about immutable variables:

let sum: u32 = vec![1,2,3,4,5,6].iter().fold(0, |sum, &val| {sum += val; sum});

error[E0384]: re-assignment of immutable variable `sum`
 --> src/main.rs:2:66
  |
2 |     let sum: u32 = vec![1,2,3,4,5,6].iter().fold(0, |sum, &val| {sum += val; sum});
  |                                                      ---         ^^^^^^^^^^ re-assignment of immutable variable
  |                                                      |
  |                                                      first assignment to `sum`

From here, you could mark sum as mutable, but the correct solution is to simply fold with sum + val, as you discovered.

Solution 2 - Vector

So it turned out there was a huge difference in my code, as I wrote

sum += x

instead of

sum + x

Well, at least I hope this question helps, in case someone gets into similar situation.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmmatyasView Question on Stackoverflow
Solution 1 - VectorShepmasterView Answer on Stackoverflow
Solution 2 - VectormmatyasView Answer on Stackoverflow