Itération en Rust : comment s'arrêter en cas d'erreur et retourner Result::Err

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : pourquoi l'itérateur ne veut-il pas s'arrêter ?

\n\n

Imaginez : vous écrivez un programme en Rust qui traite une liste de nombres — analyse des chaînes, lecture de fichiers, effectue des transformations. Vous utilisez Iterator::map pour parcourir chaque élément. Et soudain — boum ! — l'un des éléments se transforme en erreur Result::Err. Il serait logique d'arrêter immédiatement l'itération et de retourner cette erreur. Mais map continue simplement de fonctionner comme si de rien n'était. Pourquoi ? Et surtout — comment y remédier ?

\n\n

Cette question est l'une des plus populaires sur Stack Overflow parmi les débutants en Rust. Et pour cause. Les mécanismes de gestion des erreurs en Rust sont flexibles, mais nécessitent une approche réfléchie. Dans cet article, nous analyserons le problème en profondeur, examinerons plusieurs solutions et choisirons la plus élégante. C'est parti !

\n\n

Problème : map ne s'arrête pas

\n\n

Commençons par un exemple classique. Supposons que nous ayons un vecteur de chaînes que nous voulons convertir en nombres :

\n\n
fn main() {\n    let inputs = vec!["42", "hello", "100"];\n\n    let result: Vec<Result<i32, std::num::ParseIntError>> =\n        inputs.iter().map(|s| s.parse::<i32>()).collect();\n\n    println!("{:?}", result);\n}
\n\n

Ce code se compile et s'exécute. Mais qu'obtenons-nous ? Un vecteur de Result : [Ok(42), Err(ParseIntError), Ok(100)]. L'itération ne s'est pas arrêtée sur "hello", mais a continué. Pour de nombreuses tâches, c'est normal — vous voulez collecter toutes les erreurs. Mais que faire si vous avez besoin de la première exception ? Par exemple, lors du chargement d'une configuration : si un paramètre est incorrect, il est inutile de vérifier les suivants.

\n\n

Le problème est que map est une transformation paresseuse. Il ne sait pas ce qu'est un "arrêt". Il dit simplement : "Donne-moi un élément, j'applique la fonction, je retourne le résultat". Tout le contrôle de la pause et de la reprise repose sur le consommateur de l'itérateur (collect, for, fold, etc.). Et collect pour Vec va simplement jusqu'à la fin.

\n\n

Solution 1 : collect avec FromIterator (la plus populaire)

\n\n

La réponse la plus courante sur Stack Overflow est d'utiliser collect::<Result<Vec<_>, _>>(). Rust sait qu'il peut collecter un itérateur de Result en un seul Result contenant un vecteur. Si un Err est rencontré, la collecte s'arrête et cette erreur est retournée.

\n\n
fn main() -> Result<(), std::num::ParseIntError> {\n    let inputs = vec!["42", "hello", "100"];\n\n    let result: Vec<i32> =\n        inputs.iter()\n              .map(|s| s.parse::<i32>())\n              .collect::<Result<Vec<_>, _>>()?; // <-- magie !\n\n    println!("{:?}", result);\n    Ok(())\n}
\n\n

Comment cela fonctionne-t-il ? Le type Result<Vec<i32>, ParseIntError> implémente le trait FromIterator. Lorsque collect voit un Err, il le retourne immédiatement, sans traiter les éléments restants. Si tout va bien, vous obtenez Ok(vecteur). C'est court, idiomatique et efficace.

\n\n

Inconvénient : vous perdez l'information sur l'élément qui a provoqué l'erreur (sauf si vous l'enveloppez dans votre propre type). Mais pour des scripts rapides, c'est parfait.

\n\n

Solution 2 : filter_map pour ignorer les erreurs

\n\n

Parfois, vous ne voulez pas vous arrêter, mais simplement ignorer les éléments en échec. Par exemple, ne compter que les chaînes valides. Pour cela, filter_map est idéal :

\n\n
fn main() {\n    let inputs = vec!["42", "hello", "100", "abc", "7"];\n\n    let numbers: Vec<i32> = inputs.iter()\n        .filter_map(|s| s.parse::<i32>().ok()) // .ok() transforme Err en None\n        .collect();\n\n    println!("{:?}", numbers); // [42, 100, 7]\n}
\n\n

filter_map prend une

Blogs

Book Recommendations