L’ownership (propriété) est le mécanisme central qui rend Rust unique. C’est lui qui permet au compilateur de garantir la sécurité mémoire sans garbage collector. Dans cette unité, vous allez comprendre les trois règles fondamentales de l’ownership, le système de borrowing (emprunt), et pourquoi le borrow checker — parfois frustrant au début — est votre meilleur allié pour écrire du code fiable.
Le problème que Rust résout
En C, il est facile d’écrire du code qui libère une zone mémoire deux fois (double free), qui accède à de la mémoire après l’avoir libérée (use-after-free), ou qui a des data races en contexte multi-thread. Ces bugs sont à l’origine de la majorité des vulnérabilités de sécurité dans les logiciels système. Les langages avec GC (Java, Python) évitent ces bugs au prix de la performance et de la prévisibilité. Rust refuse le compromis : sécurité ET performance, garanties à la compilation.
Les trois règles de l’ownership
Tout le système repose sur trois règles simples :
- Chaque valeur en Rust a un propriétaire (owner)
- Il ne peut y avoir qu’un seul propriétaire à la fois
- Quand le propriétaire sort de portée, la valeur est libérée automatiquement
fn main() {
let s1 = String::from("bonjour"); // s1 est propriétaire
let s2 = s1; // s1 est MOVED vers s2
// println!("{}", s1); // ERREUR : s1 n'existe plus !
println!("{}", s2); // OK
} // s2 sort de portée → mémoire libérée automatiquement
Move vs Copy
Les types simples qui tiennent sur la stack (i32, f64, bool, char…) implémentent le trait Copy : ils sont dupliqués automatiquement lors d’une assignation. Les types heap (String, Vec, Box…) font un move : le propriétaire change.
let x = 5;
let y = x; // Copy : x et y sont deux valeurs indépendantes
println!("{} et {}", x, y); // OK !
Le borrowing : emprunter sans posséder
Pour passer une valeur à une fonction sans en transférer la propriété, on utilise des références avec l’opérateur &. C’est ce qu’on appelle le borrowing.
fn longueur(s: &String) -> usize {
s.len() // on emprunte s, on ne le possède pas
}
fn main() {
let s = String::from("Culte du Code");
let len = longueur(&s); // on passe une référence
println!("{} fait {} caractères", s, len); // s toujours valide !
}
Références mutables
Pour modifier une valeur empruntée, il faut une référence mutable (&mut). Le borrow checker impose une règle stricte : une seule référence mutable à la fois, et elle ne peut pas coexister avec des références immuables.
fn ajouter_texte(s: &mut String) {
s.push_str(", bienvenue !");
}
fn main() {
let mut s = String::from("Rust");
ajouter_texte(&mut s);
println!("{}", s); // "Rust, bienvenue !"
}
Le borrow checker en action
Le compilateur vérifie ces règles statiquement. Au début, les messages d’erreur peuvent sembler cryptiques, mais ils sont en réalité très précis et vous indiquent exactement où se situe le problème :
let mut s = String::from("hello");
let r1 = &s; // référence immuable
let r2 = &s; // autre référence immuable — OK
// let r3 = &mut s; // ERREUR : ne peut pas emprunter s mutuellement
// alors que r1 et r2 existent encore
- Chaque valeur a un seul propriétaire ; quand il sort de portée, la mémoire est libérée
- L’opérateur
&crée une référence (emprunt) sans transférer la propriété - Plusieurs
&Tpeuvent coexister, mais un seul&mut Tà la fois - Le borrow checker est votre filet de sécurité : ses erreurs vous protègent
📚 Formation : Rust : Développer des utilitaires système

-
Add a note