November 29, 2025•6 min

Emprunts mutables et immutables : les deux règles

m
mayo

Les règles de borrowing de Rust, appliquées par le borrow checker au moment de la compilation, assurent la memory safety et préviennent les data races sans overhead runtime. Ces règles gouvernent comment les données peuvent être accédées via des références, distinguant entre emprunts mutables (&mut T) et immutables (&T).

OK : Plusieurs &T &x, &x, &x, ... read-only, nombre illimité OK : Un seul &mut T &mut x accès exclusif, aucun autre Rejeté : Mélange &x + &mut x erreur compile-time : risque de data race Le borrow checker applique ceci au moment de la compilation aucun coût runtime, data races impossibles en code safe

Les règles de Borrowing (Appliquées par le Compiler)

  1. Soit Un Emprunt Mutable (&mut T) SOIT Plusieurs Emprunts Immutables (&T) :

    • Tu peux avoir :
      • Une référence mutable (&mut T), OU
      • N'importe quel nombre de références immutables (&T).
    • Jamais les deux en même temps pour les mêmes données.
  2. Les Références Doivent Toujours Être Valides (Pas de Dangling Pointers) :

    • Les références empruntées ne peuvent pas survivre aux données qu'elles pointent, appliqué par le système de lifetime de Rust.

Emprunts immutables (&T)

  • Accès read-only : Ne peut pas modifier les données.
  • Plusieurs autorisés : Sûr pour lectures concurrentes, car aucune modification ne peut survenir.

Exemple :

let x = 42;
let r1 = &x;  // OK: Borrowing immutable
let r2 = &x;  // OK: Autre borrow immutable
println!("{}, {}", r1, r2);  // Fonctionne bien

Emprunts mutables (&mut T)

  • Accès exclusif : Permet modification des données.
  • Aucun autre emprunt autorisé : Aucun &T ou &mut T additionnel ne peut coexister pour les mêmes données.

Exemple :

let mut x = 42;
let r1 = &mut x;  // OK: Emprunt mutable
*r1 += 1;         // Peut modifier
// let r2 = &x;   // ERREUR: Cannot borrow `x` as immutable while mutable borrow exists

Ce que le compilateur rejette

  1. Chevauchement Mutable + Immutable :

    let mut data = 10;
    let r1 = &data;      // Borrowing immutable
    let r2 = &mut data;  // ERREUR: Cannot borrow as mutable while borrowed as immutable
    
  2. Emprunts Mutables Multiples :

    let mut s = String::new();
    let r1 = &mut s;
    let r2 = &mut s;  // ERREUR: Second mutable borrow
    
  3. Références Dangereuses :

    fn dangling() -> &String {
        let s = String::from("oops");
        &s  // ERREUR: `s` meurt ici, référence pendrait
    }
    

Ce que le checker compare n'est pas l'existence des deux emprunts, mais le chevauchement de leurs durées de vie. La durée d'un emprunt se termine à sa dernière utilisation, pas à la fin du bloc :

Rejeté : l'emprunt partagé est encore vivant plus loin 1. let r1 = &data; 2. let r2 = &mut data; 3. println!("{}", r1); &data vivant jusqu'à son dernier usage ligne 3 &mut data vivant à partir de la ligne 2 les deux vivants en même temps, rustc refuse Accepté : les mêmes deux emprunts, réordonnés 1. let r1 = &data; 2. println!("{}", r1); 3. let r2 = &mut data; &data la durée se clôt au dernier usage &mut data exclusif maintenant Aucun instant n'a les deux durées vivantes : les mêmes lignes compilent désormais. temps

Pourquoi ces règles Comptent

  • Prévient les Data Races : En interdisant l'accès mutable concurrent, Rust assure la thread safety par défaut.
  • Assure Memory Safety : Pas de dangling pointers ou invalidation d'iterator, car le borrow checker applique les références valides.

Les deux règles

Emprunts immutables (&T) :

  • Plusieurs autorisés, mais pas de mutation.

Emprunts mutables (&mut T) :

  • Un seul autorisé, accès exclusif.

Violations attrapées au moment de la compilation : Pas d'overhead runtime.

Impact Réel : Ces règles permettent la concurrence sans peur, comme vu dans les crates comme Rayon pour l'itération parallèle.

Écris une fonction qui prend &mut T et appelle-la deux fois sur la même valeur. Ça compile — mais seulement parce que le premier emprunt se termine à la fin de l'appel. Garde cet emprunt dans une variable qui traverse les deux appels et tu verras la vraie erreur.

Retour au blog
Partager ::