Aller au contenu

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.

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.

▶ Essayez par vous-même

Vous pouvez aussi partir d’un vecteur vide et le remplir au fur et à mesure :

let mut numbers: Vec<i32> = Vec::new();

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]
▶ Essayez par vous-même

Même syntaxe avec crochets que pour les tableaux :

fn main() {
let fruits = vec!["pomme", "banane", "cerise"];
println!("{}", fruits[0]);
println!("Longueur : {}", fruits.len());
}
▶ Essayez par vous-même

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"),
}
}
▶ Essayez par vous-même
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);
}
▶ Essayez par vous-même
fn main() {
let numbers = vec![10, 20, 30];
for n in &numbers {
println!("{n}");
}
}
▶ Essayez par vous-même

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.

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 ».

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és
▶ Essayez par vous-même

Remarquez qu’on n’a jamais écrit le type. Rust voit les appels à push(n) et en déduit que evens est un Vec<i32>.

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"]
▶ Essayez par vous-même

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.

  • Vec<T> est une liste extensible ; on la crée avec vec![...] ou Vec::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 une Option, sans paniquer.
  • Parcourez avec for element in &vec pour emprunter les éléments au lieu de consommer le vecteur.

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