Pourquoi Rust nécessite-t-il des durées de vie explicites ? Explications avec exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi Rust oblige-t-il à spécifier les durées de vie ? Et comment cela simplifie-t-il la vie ?

\n\n

Si vous apprenez Rust, vous rencontrerez tôt ou tard cette syntaxe mystérieuse : 'a, 'b... Et une question légitime se pose : « Pourquoi dois-je spécifier explicitement les durées de vie ? D'autres langages s'en passent ! »

\n\n

Cette question est l'une des plus populaires sur Stack Overflow (des milliers de vues). Et ce n'est pas surprenant : le concept des lifetimes en Rust semble complexe jusqu'à ce que l'on en comprenne l'essence. Démêlons cela sans théorie ennuyeuse, avec des exemples concrets.

\n\n

Réponse courte : la sécurité sans ramasse-miettes

\n\n

Rust garantit la sécurité mémoire à la compilation. Il a besoin de savoir exactement combien de temps vivent les références pour éviter les références pendantes (dangling references). En Java ou Go, c'est le ramasse-miettes qui s'en charge. En C++, vous êtes responsable de la mémoire (et vous faites souvent des erreurs). Rust a choisi une troisième voie : le compilateur vérifie tout statiquement.

\n\n

Mais pourquoi le compilateur ne peut-il pas le deviner tout seul ? Il le peut – dans 80 % des cas. Cela s'appelle lifetime elision (règles d'inférence implicite). Cependant, dans des situations complexes, il a besoin de votre aide.

\n\n

Règle n°1 : Le compilateur n'est pas un médium

\n\n

Regardez cette fonction :

\n\n
fn longest(x: &str, y: &str) -> &str {\n    if x.len() > y.len() { x } else { y }\n}
\n\n

À première vue, tout semble logique. Mais Rust générera une erreur : « missing lifetime specifier ». Pourquoi ?

\n\n

Imaginez que vous passiez x – une référence vers une chaîne qui vit 5 secondes, et y – une référence vers une chaîne qui vit 1 seconde. La fonction peut retourner l'une ou l'autre. Quelle sera la durée de vie de la référence retournée ? Le compilateur ne le sait pas !

\n\n

La solution – dire explicitement : « la référence retournée vivra aussi longtemps que les deux références d'entrée » :

\n\n
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {\n    if x.len() > y.len() { x } else { y }\n}
\n\n

Le symbole 'a est une annotation de durée de vie. Nous disons : « les trois références doivent avoir la même durée de vie minimale ». Désormais, le compilateur peut vérifier que le code appelant ne détruit pas les données prématurément.

\n\n

Règle n°2 : Différentes références – différentes durées de vie

\n\n

Une erreur fréquente des débutants est de penser que tous les 'a doivent être identiques. En réalité, on peut spécifier différentes durées de vie :

\n\n
fn example<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {\n    x // Ok, on retourne une référence avec la durée de vie 'a\n    // y // Erreur ! y vit 'b, mais on a promis 'a\n}
\n\n

Ici, nous disons explicitement : x et y peuvent avoir des durées de vie différentes. Mais nous ne pouvons retourner que la référence dont la durée de vie correspond à celle promise dans le type de retour.

\n\n

Règle n°3 : Les structures peuvent aussi stocker des références

\n\n

Lorsque vous créez une structure qui contient des références, les durées de vie en Rust doivent être obligatoirement spécifiées :

\n\n
struct Book<'a> {\n    title: &'a str,\n    author: &'a str,\n}\n\nfn main() {\n    let title = String::from("Rust Book");\n    let book;\n    {\n        let author = String::from("John Doe");\n        book = Book { title: &title, author: &author };\n    } // author est détruit ici !\n    println!("{}", book.title); // Erreur ! book.author est pendante\n}
\n\n

Le compilateur ne permettra pas de compiler ce code, car book.author référence une chaîne déjà supprimée. Les lifetimes explicites en Rust permettent de détecter ces erreurs à la compilation, et non à l'exécution.

\n\n

Règle n°4 : Lifetime Elision – quand on peut ne pas écrire

\n\n

Rust est suffisamment intelligent pour déduire lui-même les durées de vie dans les cas simples. Voici quand on peut ne pas les spécifier :

\n\n
    \n
  • Une seule référence d'entrée – la durée de vie de la sortie est égale à celle de l'entrée
  • \n

Blogs

Book Recommendations