Подтвердить что ты не робот

Как суммировать вектор с помощью fold?

This В руководстве Rust хорошо объясняется механизм fold(), и этот пример кода:

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

работает как ожидалось.

Я хотел бы запустить его на векторе, поэтому, основываясь на этом примере, сначала я написал это:

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

который выдает ошибку:

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

Я предположил, что по какой-то причине это может быть связанной с ссылкой ошибкой, поэтому я изменил ее на fold(0, |sum, &val| sum += val), что привело к

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

Хм, может быть, что-то не так с закрытием? Используя {sum += x; sum }, я получил

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

снова.

После дальнейших испытаний и ошибок добавление mut в sum сработало:

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

Может ли кто-нибудь объяснить причину, по которой fold() для векторов так сильно отличается от учебника? Или, есть ли лучший способ справиться с этим?

Для справки, я использую Rust beta, 2015-04-02.

4b9b3361

Ответ 1

Вы уже поняли, что проблема +=, но я хотел бы предоставить еще несколько изложений.

В вашем случае аргументы, предоставляемые закрытию fold, являются _ и &u32. Первый тип - это еще не заданное целое число. Если вы измените свой сгиб на fold(0u32, |sum, val| sum += val), вы получите несколько другое сообщение:

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}`

Результирующее значение операции двоичного присваивания += составляет (), тип единицы измерения. Это объясняет сообщение об ошибке при изменении на fold(0, |sum, &val| sum += val):

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

Если вы измените на fold(0, |sum, &val| {sum += val ; sum}), вы получите понятную ошибку об неизменяемых переменных:

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`

Отсюда вы можете пометить sum как изменчивое, но правильным решением является просто сбросить с помощью sum + val, как вы обнаружили.


В новых версиях Rust вы можете просто sum итератор напрямую, пропустив fold:

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

Ответ 2

Итак, оказалось, что в моем коде была огромная разница, так как я писал

sum += x

вместо

sum + x.

Ну, по крайней мере, я надеюсь, что этот вопрос поможет, если кто-то попадет в аналогичную ситуацию.