Itération sur une chaîne en Rust : comment parcourir les caractères sans douleur

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

Itération sur une chaîne en Rust : comment ça fonctionne sous le capot



Vous êtes-vous déjà demandé ce qui se passe réellement lorsque vous écrivez for c in "Привет".chars() ? Si vous venez de Python ou JavaScript, où les chaînes sont simplement des tableaux de caractères, Rust peut vous sembler un professeur strict qui vous oblige à réfléchir avant chaque action. Et c'est tant mieux !



La question "How do you iterate over a string by character" sur Stack Overflow a rassemblé des milliers de vues. Et ce n'est pas sans raison. En Rust, il n'y a pas de simple string[i] — et pour de bonnes raisons. Voyons comment itérer correctement, efficacement et sans surprises.



Pourquoi Rust ne vous permet-il pas d'accéder simplement à un caractère par index ?



Tout est une question d'encodage UTF-8. Contrairement à de nombreux langages, Rust stocke les chaînes en UTF-8, et non en ASCII ou UCS-2. Cela signifie qu'un seul caractère peut occuper de 1 à 4 octets. Par exemple :



  • 'a' — 1 octet
  • 'é' — 2 octets
  • '中' — 3 octets
  • '😊' — 4 octets


Si Rust permettait de faire string[0], alors "😊"[0] renverrait non pas l'emoji, mais la moitié de sa représentation en octets — du charabia. C'est pourquoi Rust vous protège de ces erreurs au niveau du compilateur.



Les principales méthodes d'itération sur une chaîne



Rust propose trois méthodes principales d'itération, chacune avec son objectif. Le choix dépend de ce dont vous avez besoin : caractères, octets ou graphèmes.



1. Itération par caractères (char)



La méthode la plus courante est .chars(). Elle retourne un itérateur sur les caractères Unicode (type char).



fn main() {    let text = "Привет, мир! 🌍";        for c in text.chars() {        println!("{}", c);    }        // Affichage :    // П    // р    // и    // в    // е    // т    // ,    // (espace)    // м    // и    // р    // !    // (espace)    // 🌍}


Sous le capot, .chars() analyse la séquence d'octets UTF-8 et retourne chaque caractère valide. Si la chaîne contient des octets invalides, l'itérateur peut retourner std::char::REPLACEMENT_CHARACTER ('�').



Important : .chars() est en O(n). L'itérateur parcourt tous les octets, les décodant à la volée. Pour les chaînes courtes, c'est instantané, mais pour les longues (mégaoctets de texte), cela peut être perceptible.



2. Itération par octets (bytes)



Si vous avez besoin des octets bruts, utilisez .bytes(). C'est une méthode rapide, mais vous obtenez des octets, pas des caractères.



fn main() {    let text = "Hello";        for byte in text.bytes() {        println!("{}", byte);    }        // Affichage :    // 72 (H)    // 101 (e)    // 108 (l)    // 108 (l)    // 111 (o)}


Pour le texte anglais, cela équivaut à une itération par caractères. Mais pour le russe ou les emojis, non. Par exemple, "Привет" en octets fera 12 octets (2 par caractère), et "🌍" — 4 octets.



Quand l'utiliser : lorsque vous travaillez avec des données binaires, des protocoles ou que vous voulez des performances maximales sans décodage UTF-8.



3. Itération par graphèmes (grapheme clusters)



Et voici ce qui est encore plus intéressant. Parfois, un seul "caractère" visuellement est composé de plusieurs caractères Unicode. Par exemple, un drapeau de pays ou une lettre avec des signes diacritiques : "é" peut être représenté comme un seul caractère é (U+00E9) ou comme une combinaison de e + ◌́ (U+0065 + U+0301).



Pour travailler avec les graphèmes, vous devez ajouter la crate unicode-segmentation :



// Cargo.toml// [dependencies]// unicode-segmentation = "1.10"

use unicode_segmentation::UnicodeSegmentation;

fn main() { let text = "é"; // chars() retournera 1 ca

Blogs

Book Recommendations