Les vecteurs en Rust
Un vecteur (Vec) ressemble à un tableau, mais il peut grandir et rétrécir pendant l’exécution. Dans le code Rust de tous les jours, quand vous avez besoin d’une liste d’éléments, vous utiliserez un Vec bien plus souvent qu’un tableau de taille fixe.
Créer un vecteur
Section intitulée « Créer un vecteur »fn main() { let numbers: Vec<i32> = vec![1, 2, 3]; println!("{:?}", numbers);}vec![] est une macro (remarquez le !) qui construit un Vec à partir d’une liste de valeurs, un peu comme quand on écrit un tableau littéral.
Vous pouvez aussi partir d’un vecteur vide et le remplir au fur et à mesure :
let mut numbers: Vec<i32> = Vec::new();Ajouter des éléments
Section intitulée « Ajouter des éléments »Utilisez .push() pour ajouter un élément à la fin. Le vecteur doit être mut, puisque vous le modifiez :
fn main() { let mut numbers = Vec::new();
numbers.push(1); numbers.push(2); numbers.push(3);
println!("{:?}", numbers);}Sortie :
[1, 2, 3]Accéder aux éléments
Section intitulée « Accéder aux éléments »Même syntaxe avec crochets que pour les tableaux :
fn main() { let fruits = vec!["pomme", "banane", "cerise"];
println!("{}", fruits[0]); println!("Longueur : {}", fruits.len());}Pour un accès plus sûr qui ne panique pas avec un mauvais indice, utilisez .get(), qui renvoie une Option à la place (on en reparle à la page Option) :
fn main() { let fruits = vec!["pomme", "banane", "cerise"];
match fruits.get(10) { Some(fruit) => println!("Trouvé : {fruit}"), None => println!("Aucun fruit à cet indice"), }}Retirer des éléments
Section intitulée « Retirer des éléments »fn main() { let mut numbers = vec![1, 2, 3, 4, 5];
numbers.pop(); // retire le dernier élément -> [1, 2, 3, 4] numbers.remove(0); // retire par indice -> [2, 3, 4]
println!("{:?}", numbers);}Parcourir un vecteur
Section intitulée « Parcourir un vecteur »fn main() { let numbers = vec![10, 20, 30];
for n in &numbers { println!("{n}"); }}Remarquez le & devant numbers : avec for n in &numbers, la boucle emprunte chaque élément (c’est le borrowing) au lieu de prendre l’ownership (la possession) du vecteur. Sans le &, le vecteur est déplacé dans la boucle, et vous ne pouvez plus utiliser numbers ensuite. L’emprunt est ce que vous voulez presque tout le temps.
Un mot sur les génériques
Section intitulée « Un mot sur les génériques »Vous remarquerez que le type s’écrit Vec<i32> : la partie <i32> signifie « un vecteur de valeurs i32 ». Cette notation avec des chevrons s’appelle un générique, et vous la reverrez en détail à la page Génériques. Pour l’instant, lisez simplement Vec<T> comme « un vecteur qui contient des valeurs de type T ».
Exercices
Section intitulée « Exercices »1. Récupérer les nombres pairs
Section intitulée « 1. Récupérer les nombres pairs »Partez d’un vecteur vide. Parcourez les nombres de 1 à 10 et n’ajoutez que les nombres pairs. Affichez ensuite le vecteur et le nombre d’éléments qu’il contient. Indice : un nombre n est pair quand n % 2 == 0.
Voir la solution
fn main() { let mut evens = Vec::new();
for n in 1..=10 { if n % 2 == 0 { evens.push(n); } }
println!("{:?}", evens); println!("{} nombres pairs trouvés", evens.len());}Sortie :
[2, 4, 6, 8, 10]5 nombres pairs trouvésRemarquez qu’on n’a jamais écrit le type. Rust voit les appels à push(n) et en déduit que evens est un Vec<i32>.
2. Une pile d’assiettes
Section intitulée « 2. Une pile d’assiettes »Empilez trois assiettes dans un vecteur : "bleue", "verte", puis "rouge". Retirez deux assiettes du dessus avec .pop() et affichez chacune d’elles. Enfin, affichez ce qui reste. Indice : .pop() renvoie une Option, donc affichez-la avec {:?}.
Voir la solution
fn main() { let mut plates = Vec::new(); plates.push("bleue"); plates.push("verte"); plates.push("rouge");
println!("Retirée : {:?}", plates.pop()); println!("Retirée : {:?}", plates.pop()); println!("Reste : {:?}", plates);}Sortie :
Retirée : Some("rouge")Retirée : Some("verte")Reste : ["bleue"]pop() prend toujours le dernier élément ajouté, comme quand on prend l’assiette du dessus d’une pile. Il renvoie Some(...) et non la valeur seule, parce que le vecteur pourrait être vide. Dans ce cas, vous obtiendriez None au lieu d’un plantage.
Récapitulatif
Section intitulée « Récapitulatif »Vec<T>est une liste extensible ; on la crée avecvec![...]ouVec::new()..push()ajoute à la fin ;.pop()retire le dernier élément ;.remove(i)retire par indice.vec[i]panique avec un mauvais indice ;.get(i)renvoie plutôt uneOption, sans paniquer.- Parcourez avec
for element in &vecpour emprunter les éléments au lieu de consommer le vecteur.
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. Que se passe-t-il quand on accède à un Vec avec un mauvais indice, comme numbers[10] ?
2. Quelle méthode permet de consulter un indice sans risquer de panique ?
3. À quoi sert le & dans for n in &numbers ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Storing Lists of Values with Vectors — The Rust Book (en anglais) : créer, lire et modifier des vecteurs, et pourquoi on ne peut pas faire de
pushtant qu’on garde une référence. - Vectors — Rust by Example (en anglais) : un exemple exécutable qui montre les opérations les plus courantes sur un
Vec. Vec— documentation de la bibliothèque standard (en anglais) : la liste complète des méthodes, commeinsert,retain,extendetcontains.- La macro
vec!— documentation de la bibliothèque standard (en anglais) : toutes les formes devec!, y comprisvec![0; 10]pour répéter une valeur.