Blog · 2026-06-18Blog · 2026-06-18

Le borrow checker de Rust, expliqué simplement Rust's borrow checker, explained simply

Pourquoi le compilateur Rust refuse votre code, et la règle unique — un &mut, ou autant de & que vous voulez, jamais les deux — qui explique 90 % de ses refus.Why the Rust compiler rejects your code, and the single rule — one &mut, or as many & as you want, never both — behind 90% of its refusals.

RustBorrow checkerOwnership

Si vous débarquez d’un langage à ramasse-miettes (Java, Python, Go…), Rust vous accueille avec une porte fermée : le borrow checker. Il refuse de compiler du code qui semble parfaitement correct. La bonne nouvelle : derrière ses messages intimidants se cache une seule règle, et une fois qu’on la tient, l’essentiel de ses refus devient prévisible.

Emprunter au lieu de posséder

En Rust, chaque valeur a un propriétaire unique. Mais on n’a pas toujours besoin de posséder une donnée pour la lire ou la modifier — il suffit de l’emprunter, avec une référence :

fn longueur(s: &String) -> usize {  // & : on emprunte, on ne possède pas
    s.len()
}

let nom = String::from("Ada");
let n = longueur(&nom);             // on prête `nom` le temps de l'appel
println!("{nom} fait {n} lettres"); // `nom` est toujours à nous

Deux sortes d’emprunts existent : &T (partagé, lecture seule) et &mut T (exclusif, lecture-écriture). Et c’est là qu’intervient la règle.

La règle unique : aliasing XOR mutation

À tout instant, pour une donnée : soit un seul &mut (et rien d’autre), soit autant de & que vous voulez — jamais les deux en même temps.

C’est tout. Le borrow checker ne fait que vérifier ça. Ce code échoue :

let mut v = vec![1, 2, 3];
let premier = &v[0];     // un emprunt partagé est vivant…
v.push(4);               // …et on tente de muter en même temps → refusé
println!("{premier}");

Pourquoi ? Parce que push peut réallouer le vecteur en mémoire, rendant premier pendouillant. Le compilateur ne contraint pas le langage : il retourne la définition d’une course de données en interdiction. Ce qui était un bug subtil à l’exécution devient une erreur à la compilation.

Comment satisfaire le checker

La plupart des refus se règlent en resserrant la durée de vie d’un emprunt : utilisez la référence, puis laissez-la mourir avant de muter.

let mut v = vec![1, 2, 3];
let premier = v[0];      // on copie la valeur au lieu d'emprunter
v.push(4);               // plus aucun emprunt vivant → OK
println!("{premier}");

Une fois cette règle intégrée, vous arrêtez de vous battre contre le compilateur : vous l’entendez énoncer un théorème sur votre code.

Coming from a garbage-collected language (Java, Python, Go…), Rust greets you with a closed door: the borrow checker. It refuses to compile code that looks perfectly fine. The good news: behind its intimidating messages hides a single rule, and once you hold it, most of its refusals become predictable.

Borrow instead of own

In Rust, every value has a single owner. But you don’t always need to own data to read or change it — you can just borrow it, with a reference:

fn length(s: &String) -> usize {   // & : we borrow, we don't own
    s.len()
}

let name = String::from("Ada");
let n = length(&name);             // we lend `name` for the call
println!("{name} is {n} letters"); // `name` is still ours

There are two kinds of borrows: &T (shared, read-only) and &mut T (exclusive, read-write). And that’s where the rule comes in.

The single rule: aliasing XOR mutation

At any moment, for one piece of data: either one &mut (and nothing else), or as many & as you want — never both at once.

That’s it. The borrow checker only ever verifies this. This code fails:

let mut v = vec![1, 2, 3];
let first = &v[0];       // a shared borrow is alive…
v.push(4);               // …and we try to mutate at the same time → rejected
println!("{first}");

Why? Because push may reallocate the vector in memory, leaving first dangling. The compiler doesn’t constrain the language: it flips the definition of a data race into a prohibition. What used to be a subtle runtime bug becomes a compile-time error.

How to satisfy the checker

Most refusals are fixed by tightening a borrow’s lifetime: use the reference, then let it die before you mutate.

let mut v = vec![1, 2, 3];
let first = v[0];        // copy the value instead of borrowing
v.push(4);               // no live borrow left → OK
println!("{first}");

Once this rule clicks, you stop fighting the compiler: you hear it state a theorem about your code.

Tous les articlesAll articles