ProgrammationDéveloppeur Rust

Qu'est-ce que les lifetimes en Rust et pourquoi sont-ils nécessaires lors de l'utilisation des références ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En Rust, les lifetimes définissent la portée des références, afin que le compilateur puisse s'assurer que les pointeurs ne deviennent pas suspendus (pas de références suspendues). Cela permet de garantir la sécurité de la mémoire pendant la compilation sans nécessiter de ramasse-miettes.

Lorsque vous travaillez avec des références, Rust exige que vous spécifiez explicitement leur durée de vie, lorsque le compilateur ne peut pas le déduire lui-même. Cela se fait généralement en utilisant la syntaxe 'a:

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

Ici, les deux paramètres et la valeur de retour ont la même lifetime, ce qui garantit que : la référence retournée ne vivra pas plus longtemps que l'un des arguments.

Les lifetimes ne modifient pas la durée de vie des données, mais décrivent seulement cela au compilateur.

Question piège

Est-il possible de retourner une référence à une variable locale à l'intérieur d'une fonction ?

Non, ce n'est pas possible : car une telle variable sera détruite à la sortie de la fonction. Exemple:

fn foo() -> &String { // erreur de compilation ! let s = String::from("hello"); &s } // la référence à s devient invalide

Le compilateur empêchera la compilation de ce code : il vous protégera d'utiliser des références sur des données détruites.

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet


Histoire

L'équipe a rencontré de nombreuses fuites de mémoire lorsque des fonctions retournaient accidentellement des références à des tampons locaux. Cela ne fonctionnait pas, et seul le compilateur, qui a commencé à se plaindre des lifetimes, a sauvé la situation. En raison de la fréquence de telles erreurs, il a été établi une règle de spécifier explicitement le lifetime si la fonction travaille avec des structures complexes avec des références imbriquées.


Histoire

Un code générique a été créé dans le projet pour mettre en cache des données. En raison d'une conception incorrecte des paramètres génériques de lifetime, des erreurs du type "cannot infer lifetime" se produisaient et il est devenu impossible de déduire la durée de vie des données stockées dans le cache. Cela a conduit à la configuration des annotations de lifetime par essai et erreur, jusqu'à ce qu'il soit décidé de séparer les données mises en cache et non mises en cache dans différentes structures.


Histoire

Un de mes collègues a essayé de mettre en œuvre un pool de connexions en utilisant des références aux objets de connexion, mais il n'a pas pris en compte que les lifetimes des connexions ne coïncident pas avec la durée de vie du pool. Au final, des références suspendues sont apparues après la libération des connexions, ce qui n'a été remarqué qu'à l'étape des tests d'intégration. Après cela, le projet est passé à des wrappers sûrs (Arc<Mutex<T>>).