Retour au cours

backend / rust

Variables et mutabilité

Leçon 21 exercice

Explication

Ce que vous allez apprendre

  • Comprendre pourquoi une variable Rust est immuable par défaut
  • Rendre une variable mutable explicitement avec mut
  • Utiliser le shadowing pour redéclarer une variable avec un nouveau type ou une nouvelle valeur
  • Distinguer une constante (const) d'une variable immuable simple (let)
  • Comprendre la différence entre muter une référence et muter la valeur pointée

Dans quel contexte ?

Un développeur qui vient de Python ou JavaScript écrit let x = 5; puis tente, quelques lignes plus loin, de faire x = 6; — et le compilateur Rust refuse catégoriquement de compiler, avec un message explicite : "cannot assign twice to immutable variable". Ce refus, qui surprend au début, est en réalité l'un des piliers de la sécurité de Rust : il force à déclarer intentionnellement quelles variables peuvent réellement changer.

D'abord, il faut assimiler ce renversement de philosophie

Dans la quasi-totalité des langages, une variable est mutable par défaut, et il faut un mot-clé spécial (const, final, readonly) pour la rendre immuable. Rust fait exactement l'inverse : let x = 5 crée une variable immuable, et il faut explicitement écrire let mut y = 5 pour autoriser sa modification ultérieure.

Ce choix n'est pas arbitraire : en pratique, la grande majorité des variables dans un programme ne sont jamais réassignées après leur création. Rendre l'immuabilité par défaut pousse à documenter intentionnellement les rares cas qui ont réellement besoin de changer.

Une fois cette base acquise, un mécanisme surprenant complète le tableau : le shadowing

Le "shadowing" permet de redéclarer une variable avec le même nom via un nouveau let, créant en réalité une toute nouvelle variable qui masque l'ancienne. Contrairement à mut, le shadowing autorise même de changer le type de la donnée au passage.

MécanismeSyntaxeCe qu'il permet
let simplelet x = 5;Variable immuable, un seul type, jamais réassignée
let mutlet mut y = 5; y = 6;Variable mutable, même type, réassignable
Shadowinglet z = 5; let z = format!("{}", z);Nouvelle variable, type potentiellement différent
constconst MAX: u32 = 100;Toujours immuable, type obligatoire, valeur figée à la compilation

Prérequis

Aucune connaissance préalable de Rust n'est nécessaire au-delà de la première leçon (installation et premier programme).

Il reste une nuance subtile entre mut sur une référence et mut sur la valeur

let mut compteur = 0; rend compteur mutable. let reference = &mut compteur; crée ensuite une référence mutable exclusive vers cette variable : *reference += 1 modifie alors la valeur pointée, pas la référence elle-même. Cette distinction entre "la référence peut changer où elle pointe" et "on peut modifier ce qui est pointé" deviendra centrale dans la prochaine leçon sur le borrowing.

Piège fréquent

Une variable rendue mutable avec mut mais jamais réellement modifiée déclenche un avertissement du compilateur ("variable does not need to be mutable"). Ce n'est pas une erreur bloquante, mais un signal fort que ton code contient une intention mal exprimée — retire le mut inutile dès que ce warning apparaît.

Une bonne pratique à adopter dès maintenant

Bonne pratique

Laisse toujours let (sans mut) comme choix par défaut, et n'ajoute mut qu'au moment précis où le compilateur te force à le faire. Cette discipline, qui semble contraignante au début, documente immédiatement l'intention de chaque variable pour quiconque relit ton code plus tard.

Maintenant que tu maîtrises la mutabilité de base, la prochaine leçon explore les types fondamentaux de Rust en détail, avant d'aborder le concept qui distingue vraiment ce langage de tous les autres : l'ownership.

Commandes & code

Variables et mutabilité

En Rust, tout est immuable par défaut : la mutabilité doit être explicitement demandée.

rust
fn main() {
    // Immuable par defaut : erreur de compilation si on tente de reassigner
    let x = 5;
    // x = 6; // ERREUR: cannot assign twice to immutable variable

    // mut rend la variable mutable
    let mut y = 5;
    y = 6;
    println!("{}", y);

    // Shadowing : redeclarer le meme nom avec `let` cree une NOUVELLE variable
    let z = 5;
    let z = z * 2; // z vaut maintenant 10, type potentiellement different
    let z = format!("valeur: {}", z); // z devient une String ici
    println!("{}", z);

    // Constantes : toujours immuables, type obligatoire, evaluees a la compilation
    const MAX_POINTS: u32 = 100_000;
    println!("{}", MAX_POINTS);

    // Portee (scope) : une variable vit jusqu'a la fin de son bloc
    let a = 10;
    {
        let a = 20; // masque le `a` externe dans ce bloc
        println!("interieur: {}", a);
    }
    println!("exterieur: {}", a);

    // mut sur une reference vs mut sur la valeur pointee : nuance importante
    let mut compteur = 0;
    let reference = &mut compteur; // reference mutable exclusive
    *reference += 1;
    println!("{}", compteur);
}

Résumé

  • let = immuable par défaut, let mut = mutable : un choix explicite et volontaire.
  • Le shadowing permet de réutiliser un nom avec un type ou une valeur différente sans mut.
  • Une constante (const) est toujours immuable et doit avoir un type explicite.
  • Ce choix "immuable par défaut" est une des bases de la sécurité mémoire de Rust.

Exercices pratiques

1 disponible
1

Mission : corriger un compteur qui refuse de compiler

Objectif : Diagnostiquer une erreur de mutabilite dans un code fourni et choisir entre mut, shadowing et const selon le bon usage.

Contexte

Un collegue t'envoie un extrait de code qui ne compile pas :

rust
fn main() {
    let compteur = 0;
    compteur = compteur + 1;
    let limite = 100;
    limite = limite + 1;
    println!("{} / {}", compteur, limite);
}

Il pense avoir trouve un bug du compilateur. Ta mission : identifier precisement ce qui bloque, et proposer la correction la plus idiomatique possible ligne par ligne.

Résoudre l’exercice →