ProgrammationDéveloppeur Fullstack

Expliquez comment Rust gère la lecture et l'analyse des chaînes en nombres (par exemple, de String à i32) ? Quels pièges existent lors de l'utilisation de la méthode parse, et comment gérer correctement les erreurs de conversion ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

Rust offre des moyens standard pratiques pour convertir des chaînes en nombres via le trait FromStr. La méthode .parse::<T>() est la plus utilisée et peut être appelée sur des chaînes et des tranches.

Contexte de la question

Dans de nombreux langages, la conversion d'une chaîne en un nombre est une tâche courante, mais en Rust, cela se fait de manière maximale sécurisée et transparente, les erreurs de traitement faisant partie du contrat de la bibliothèque standard, et non des exceptions d'exécution.

Problème

.parse::<T>() retourne un résultat de type Result<T, ParseIntError> (ou un équivalent pour d'autres types), ce qui oblige à traiter explicitement les échecs. Une erreur fréquente est d'ignorer la possibilité d'erreur, d'utiliser unwrap() sans analyse, ce qui fait que le programme plante en cas d'entrée de données incorrectes, au lieu de fournir un message d'erreur approprié.

Solution

Pour convertir des chaînes, on utilise la méthode parse. Sa signature est :

let num: i32 = "42".parse().unwrap();

Mais il est préférable de gérer l'erreur :

let s = "abc"; match s.parse::<i32>() { Ok(n) => println!("Nombre obtenu : {}", n), Err(e) => println!("Erreur d'analyse : {e}"), }

Caractéristiques clés :

  • Pour chaque type numérique, FromStr est implémenté, mais les limites exactes ne sont pas explicites : les espaces, les signes, les débordements sont pris en compte différemment.
  • Les erreurs sont retournées sous forme de Result, et non par panique ou exception.
  • Tout type disposant d'une implémentation de FromStr (y compris les types personnalisés) peut être la cible de .parse().

Questions piégeuses.

Peut-on utiliser parse sans spécifier le type de résultat ?

Non, sans une précision du type (ou une inférence implicite de type), Rust renverra une erreur car il ne sait pas quel type convertir.

Que se passe-t-il si l'on essaie d'analyser une chaîne contenant des caractères non numériques en un nombre ?

La méthode renverra une erreur (Err(...)), elle ne déclenchera pas de panique. L'erreur implémente le trait Debug, ce qui est pratique pour l'affichage.

let num: Result<u32, _> = "not_a_number".parse(); assert!(num.is_err());

Peut-on utiliser unwrap après parse, si l'on est certain du contenu ?

Techniquement oui, mais c'est un anti-pattern. Si la chaîne est soudainement invalide, le programme se terminera de manière inattendue.

Erreurs typiques et anti-patterns

  • Utilisation de unwrap() sans traitement des erreurs
  • Non-utilisation de trim avant la conversion, si l'entrée provient de l'utilisateur
  • Erreur de type lors de l'analyse (parse::<String>()) au lieu du type numérique cible

Exemple de la vie réelle

Cas négatif

Un utilitaire console lit un nombre de l'utilisateur et utilise .parse().unwrap(). Avec une entrée incorrecte accidentelle, le programme plante soudainement, l'utilisateur ne comprend pas la raison.

Avantages :

  • Code plus simple

Inconvénients :

  • Risque de sortie du programme, mauvaise expérience utilisateur

Cas positif

L'entrée est d'abord nettoyée des espaces, puis parse est utilisé dans un scénario avec match ou si nécessaire — map_err pour retourner une erreur définie. Les erreurs sont traitées correctement, avec un message d'erreur clair.

Avantages :

  • Le programme ne plante pas sur une entrée incorrecte ; les erreurs sont informatives.
  • Le code est plus sûr et plus facile à maintenir.

Inconvénients :

  • Un peu plus de code lors du traitement de l'entrée