web-dev-qa-db-fra.com

Comment additionner un vecteur en utilisant fold?

This Rust tutoriel explique bien le mécanisme fold(), et cet exemple de code:

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

fonctionne comme prévu.

Je voudrais l'exécuter sur un vecteur, donc sur la base de cet exemple, j'ai d'abord écrit ceci:

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

qui a jeté une erreur:

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

J'ai deviné que cela pouvait être une erreur liée à la référence pour une raison quelconque, j'ai donc changé cela en fold(0, |sum, &val| sum += val), ce qui a entraîné

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

Hm, peut-être que quelque chose ne va pas avec la fermeture? En utilisant {sum += x; sum }, J'ai obtenu

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

encore.

Après d'autres essais et erreurs, l'ajout de mut à sum a fonctionné:

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

Quelqu'un pourrait-il expliquer la raison pour laquelle fold() pour les vecteurs diffère tellement du tutoriel? Ou existe-t-il une meilleure façon de gérer cela?

Pour référence, j'utilise Rust beta, 2015-04-02.

28
mmatyas

Vous avez déjà compris que += Est le problème, mais j'aimerais fournir plus d'informations.

Dans votre cas, les arguments fournis pour la fermeture de fold sont _ Et &u32. Le premier type est un entier non encore spécifié. Si vous changez votre appel de repli en fold(0u32, |sum, val| sum += val), vous obtiendrez un message légèrement différent:

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

La valeur de résultat de l'opération d'affectation binaire += Est (), Le type d'unité. Cela explique le message d'erreur lorsque vous êtes passé à fold(0, |sum, &val| sum += val):

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

Si vous passez à fold(0, |sum, &val| {sum += val ; sum}), vous obtenez alors une erreur compréhensible sur les variables immuables:

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`

À partir de là, vous pourriez marquer sum comme mutable, mais la bonne solution est de simplement plier avec sum + val, Comme vous avez découvert.


Dans les versions plus récentes de Rust, vous pouvez également simplement sum l'itérateur directement, en sautant fold:

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

Il s'est donc avéré qu'il y avait une énorme différence dans mon code, comme je l'ai écrit

sum += x

au lieu de

sum + x.

Eh bien, au moins j'espère que cette question vous aidera, au cas où quelqu'un se retrouverait dans une situation similaire.

9
mmatyas