Créer des listes avec Vec

RustBeginner
Pratiquer maintenant

Introduction

Une variable stocke une seule valeur, mais de nombreux programmes ont besoin d’une liste ordonnée dont la longueur peut varier. Le Vec<T> de Rust est une séquence extensible : chaque élément est de type T, les valeurs conservent leur ordre et le vecteur est propriétaire de ses éléments.

Vous allez créer une liste de commandes pour un café, lire une position en toute sécurité, parcourir chaque commande sans consommer la liste, puis mettre à jour chaque chaîne stockée au moyen de références mutables.

Créer et agrandir un vecteur

Dans cette étape, vous allez ajouter trois chaînes possédées à un vecteur initialement vide.

Accédez au projet préparé et ouvrez son code source :

cd /home/labex/project/cafe-orders
nano src/main.rs

La déclaration Vec<String> signifie « un vecteur dont les éléments sont des valeurs String possédées ». Il s’agit de la même notation avec des chevrons que celle vue dans Option<u32> : ici, le type de l’élément contenu est String. Vous apprendrez à définir ce type réutilisable dans le laboratoire consacré aux génériques. Vec::new() crée un vecteur vide. La liaison est déclarée avec mut, car l’ajout d’éléments modifie le vecteur.

Remplacez le commentaire de l’étape 1 par trois appels à push :

    orders.push(String::from("Latte"));
    orders.push(String::from("Tea"));
    orders.push(String::from("Cake"));

push ajoute un élément à la fin du vecteur tout en conservant l’ordre d’insertion. Enregistrez avec Ctrl+O, appuyez sur Entrée, puis quittez avec Ctrl+X. Vérifiez et exécutez le programme :

cargo check
cargo run --quiet

La sortie doit être la suivante :

Order count: 3
Orders: ["Latte", "Tea", "Cake"]

len() renvoie trois éléments. Le paramètre :? utilise le formatage de débogage de Rust pour afficher le vecteur complet, notamment les guillemets autour de ses chaînes.

Lire une position en toute sécurité

Dans cette étape, vous allez lire la deuxième position du vecteur sans risquer de provoquer une panique due à un index hors limites.

Les positions d’un vecteur commencent à zéro : l’index 1 désigne donc la deuxième commande. La méthode get renvoie un Option<&String> : Some contient une référence partagée lorsque la position existe, tandis que None représente une position absente. Cette référence vous permet de lire l’élément tout en laissant le vecteur en rester propriétaire.

Ouvrez le code source :

nano src/main.rs

Remplacez le commentaire de l’étape 2 par le code suivant :

    match orders.get(1) {
        Some(order) => println!("Second order: {order}"),
        None => println!("Second order: missing"),
    }

Ce code lit l’élément sans déplacer sa valeur String hors du vecteur. Enregistrez et quittez, puis exécutez :

cargo run --quiet

Une nouvelle dernière ligne doit apparaître :

Second order: Tea

Cette ligne prouve à la fois que la position 1 existe et que l’ordre d’insertion a été conservé.

Parcourir avec une référence partagée

Dans cette étape, vous allez parcourir toutes les commandes tout en conservant le vecteur disponible par la suite.

Écrire &orders emprunte le vecteur au lieu de le déplacer dans la boucle for. Chaque valeur de la boucle est donc une référence partagée vers l’une des valeurs String stockées.

Ouvrez le code source :

nano src/main.rs

Remplacez le commentaire de l’étape 3 par cette boucle suivie d’une vérification :

    for order in &orders {
        println!("Queued: {order}");
    }
    println!("Stored after display: {}", orders.len());

Enregistrez et quittez, puis exécutez :

cargo run --quiet

Les nouvelles lignes doivent être les suivantes :

Queued: Latte
Queued: Tea
Queued: Cake
Stored after display: 3

Le nombre final reste utilisable après la boucle, car celle-ci a emprunté le vecteur et a rendu chaque référence partagée avant de passer à l’itération suivante.

Mettre à jour avec des références mutables

Dans cette étape, vous allez emprunter chaque élément du vecteur de manière mutable et le modifier sur place avant l’exécution de la boucle d’affichage.

Une seule référence mutable vers une valeur peut être active à la fois. Une boucle for sur &mut orders respecte cette règle : elle fournit une référence mutable vers un élément, l’utilise pendant l’itération en cours, puis passe à l’élément suivant.

Ouvrez le code source :

nano src/main.rs

Remplacez le commentaire de l’étape 4 par le code suivant :

    for order in &mut orders {
        order.push_str(" - ready");
    }

push_str ajoute du texte emprunté à chaque valeur String possédée. Pour cet appel de méthode, Rust utilise automatiquement la valeur String mutable située derrière chaque référence.

Enregistrez et quittez, puis vérifiez et exécutez :

cargo check
cargo run --quiet

La sortie complète doit être la suivante :

Order count: 3
Orders: ["Latte", "Tea", "Cake"]
Second order: Tea
Queued: Latte - ready
Queued: Tea - ready
Queued: Cake - ready
Stored after display: 3

Les lignes de la file mise à jour prouvent que tous les éléments ont été modifiés sur place. Le nombre final prouve que le vecteur est toujours propriétaire des trois mêmes chaînes.

Résumé

Vous avez créé et agrandi un Vec<String>, consulté une position en toute sécurité avec get, parcouru le vecteur sans le consommer et mis à jour chaque élément au moyen de références mutables.