est un langage de programmation compilé multi-paradigme qui met l'accent sur la performance, la sûreté des types et la concurrence. Il garantit la , ce qui signifie que toutes les références pointent vers une mémoire valide, sans nécessiter l'utilisation de techniques de gestion de la mémoire automatisée telles que le ramasse-miettes. Afin d'assurer la sécurité de la mémoire et d'empêcher une situation de compétition aux données, son « vérificateur d'emprunts » suit la durée de vie des objets de toutes les références dans un programme à la compilation.
Rust a été influencé par des idées issues de la programmation fonctionnelle, notamment immutabilité, fonction d'ordre supérieur et les types algébriques. Il est populaire pour la programmation système.
Graydon Hoare, développeur de logiciels, a créé Rust en tant que projet personnel alors qu'il travaillait à Mozilla Research en 2006. Mozilla a officiellement parrainé le projet en 2009. Dans les années qui ont suivi la première version stable en , Rust a été adopté par des entreprises telles que Amazon, Discord, Dropbox, Google (Alphabet), Meta, et Microsoft. En , il est devenu le premier langage autre que le C et l'assembleur à être pris en charge dans le développement du noyau Linux..
Rust a été adopté très rapidement et ce fut une surprise, et a été étudié dans le cadre de la recherche sur la théorie des langages de programmation..
Selon le Stack Overflow Survey 2025, c'est le langage le plus apprécié dans ce sondage.
Histoire Origines (2006-2012)
Rust est né d'un projet personnel initié en 2006 par Graydon Hoare, employé de Mozilla Research.. Mozilla a commencé à parrainer le projet en 2009 dans le cadre du développement continu d'un moteur de navigateur expérimental appelé Servo., qui a été officiellement annoncé par Mozilla en 2010.. Au cours de la même année, le travail est passé du compilateur initial écrit en OCaml à un compilateur auto-hébergé basé sur LLVM écrit en Rust. Le nouveau compilateur Rust a réussi à se compiler lui-même en 2011.
Évolution (2012-2019)
Le système de types de Rust a subi des changements importants entre les versions 0.2, 0.3 et 0.4. Dans la version 0.2, publiée en , les classes ont été introduites pour la première fois.. Quatre mois plus tard, la version 0.3 ajoute les destructeurs et le polymorphisme, grâce à l'utilisation d'interfaces.. En , la version 0.4 a été publiée, ajoutant traits comme moyen d'héritage. Les interfaces ont été combinées avec les traits et supprimées en tant que fonctionnalité séparée ; et les classes ont été remplacées par une combinaison d'implémentations et de types structurés..
Au début des années 2010, la gestion de la mémoire par le système de propriété a été progressivement consolidée pour éviter les bogues de mémoire. En 2013, le ramasse-miettes a été supprimé, avec les règles de propriété en place. En , le rédacteur en chef du , Andrew Binstock, a commenté les chances de Rust de devenir un concurrent de C++, au même titre que D, Go, et Nim. Selon Binstock, alors que Rust était "largement considéré comme un langage remarquablement élégant", l'adoption a ralenti parce qu'il changeait radicalement d'une version à l'autre. La première version stable, Rust 1.0, a été annoncée le ...
Le développement du moteur de navigation Servo s'est poursuivi parallèlement à la propre croissance de Rust. En , Firefox 57 a été publié en tant que première version intégrant des composants de Servo, dans un projet nommé "Firefox Quantum"..
Les licenciements de Mozilla et la Fondation Rust (2020-présent)
En , Mozilla a licencié 250 de ses 1 000 employés dans le monde, dans le cadre d'une restructuration de l'entreprise causée par la pandémie de COVID-19... L'équipe à l'origine de Servo a été dissoute. L'événement a soulevé des inquiétudes quant à l'avenir de Rust, car certains membres de l'équipe étaient des contributeurs actifs à Rust.. La semaine suivante, la Rust Core Team a reconnu l'impact sévère des licenciements et a annoncé que des plans pour une fondation Rust étaient en cours. Le premier objectif de la fondation serait de prendre possession de toutes les marques déposées et de tous les noms de domaine, et d'assumer la responsabilité financière de leurs coûts..
Le , la formation de la Rust Foundation a été annoncée par ses cinq entreprises fondatrices (AWS, Huawei, Google, Microsoft, et Mozilla)... Dans un blog publié le , Google a annoncé le support de Rust au sein du Android Open Source Project comme alternative à C/C++..
Le , l'équipe de modération, qui était chargée de faire respecter les normes de la communauté et le Code de conduite, a annoncé sa démission "pour protester contre le fait que l'équipe principale ne rende de comptes à personne d'autre qu'à elle-même".. En , l'équipe principale de Rust, d'autres programmeurs principaux et certains membres du conseil d'administration de la Fondation Rust ont mis en œuvre des réformes de gouvernance en réponse à l'incident..
La Fondation Rust a publié le un projet de nouvelle politique de marque déposée, révisant ses règles sur la façon dont le logo et le nom Rust peuvent être utilisés, ce qui a entraîné des réactions négatives de la part des utilisateurs et des contributeurs de Rust..
Caractéristiques Syntaxe La syntaxe du langage est similaire à celle du C, étant constituée de blocs de code délimités par des accolades et de structures de contrôle comme if, else, while et for. Cependant, la sémantique de Rust est différente. En effet, les blocs et les structures de contrôle sont des expressions, comme on peut le voir dans l'exemple :let x = if n < 10 { n } else { n - 10 };En C, une telle opération n'est pas « intelligible » pour le compilateur ; il faudra soit encapsuler le bloc conditionnel dans une autre fonction, soit utiliser un opérateur ternaire int x = (n < 10) ? n : n - 10;. L'utilisation d'expressions rapproche ainsi Rust de langages fonctionnels comme Haskell ou OCaml.
Valeur et mutabilité Dans la plupart des langages de programmation, un identificateur correspond à une et est donc modifiable par défaut. En Rust, c'est l'inverse, un identificateur correspond à une valeur figée : le mot-clé let déclare par défaut un identificateur associé à une entité immuable qui reçoit une valeur initiale au moment de l'exécution, valeur qui ne sera plus modifiée. La modification d’une valeur introduite par let nécessite soit l’utilisation de sa variante let mut, soit que le type de la valeur utilise la « variabilité intérieure ». Ce fonctionnement permet de contrôler les entités qui sont effectivement autorisées à changer. Le type associé à un identificateur est inféré du contexte à chaque fois que c'est possible.
Le mot-clé const, utilisé à la place d’un let, introduit une valeur constante connue dès la compilation. Contrairement à let, il ne permet pas l’inférence et la valeur initiale doit être une expression constante..
fn main() { // Déclaration de variables let mut a = 5; // a est une variable modifiable let b = a * 2; // b est non modifiable et du même type que a
// Constantes const C: u32 = 5; // déclaration d'une constante entière non-signée const C: u8 = b - 3; // interdit car `b - 3` n'est pas une expression constante (b non défini à la compilation) const C = 5; // interdit car le type de c n'est pas précisé
// Altération C = 3; // illégal car c est une constante b = 3; // illégal car b est une variable immuable a = 2; // autorisé car a est déclaré comme "mut" let a = a + 5; // autorisé une nouvelle variable a est créée valant 7, // l'ancienne variable a est "couverte" par la nouvelle (shadowing)
// Vérification des valeurs assert_eq!(a, 5); // faux assert_eq!(b, 10); // vrai }
Énumérations et filtrage par motif Rust permet la définition de types sommes à l'aide du mot-clé enum. On peut utiliser ces types sommes avec du filtrage par motif, en utilisant par exemple le mot-clé match.
Exemple : // On crée un type « Forme » pour décrire des formes géométriques. enum Forme { Point, // une forme peut être un point, sans données attachées. Cercle(f64), // une forme peut être un cercle, caractérisé par son rayon. Rectangle(f64, f64), // une forme peut être un rectangle, caractérisé par les longueurs de deux de ses côtés adjacents. }
// Calcule l'aire d'une forme géométrique. fn aire(f: Forme) -> f64 { match f { // Filtrage par motif avec « match » Forme::Point => 0.0, Forme::Cercle(rayon) => rayon * rayon * 3.1415926535897932384626433832795, Forme::Rectangle(cote_a, cote_b) => cote_a * cote_b,
Certaines énumérations font partie de la bibliothèque standard, comme Option, permettant d'éviter l'utilisation du pointeur NULL..
Métaprogrammation permise grâce au filtrage par motif
Programmation générique Afin de garantir la programmation générique, le langage Rust implémente son propre système de métaprogrammation basé sur les traits. Ainsi, un développeur souhaitant mettre en place une fonction générique sera dans l’obligation d’expliciter les différents traits utilisés dans sa fonction, son objet ou sa méthode.
Exemple de l’implémentation du tri-bulle de manière générique :fn tri_bulle<T: std::cmp::PartialOrd>(liste: &mut Vec<T>) { // Ici, on a besoin de l’opérateur de comparaison < implémenté par le trait // PartialOrd let mut i = 0;
while i < (liste.len() - 1) { if liste[i] < liste[i + 1] { liste.swap(i, i + 1); i = 0; } else { i += 1;
}Ainsi, toute liste de valeurs prenant en charge l’opérateur de comparaison « < » pourra être passée comme argument pour cette fonction.
Définition des méthodes communes par le biais de traits Les traits sont assimilables aux interfaces en Java ou aux classes abstraites en C++ : Ils définissent les méthodes qui seront proposées par les structures les implémentant. Ils sont des composants centraux du langage, étant donné que les opérations comme les additions sont définies via l’implémentation de traits. Ces derniers peuvent également proposer une implémentation générique de certaines de leurs fonctions à condition que ces dernières ne requièrent pas l’utilisation de données stockées dans les objets.
Exemple de définition d‘un trait :trait Polygone { fn nombre_cotes(&self) -> usize;
fn points(&self) -> Vec<(f32, f32)>;
// Il n’existe pas de méthode simple et générique pour calculer l’aire d’un // polygone fn aire(&self) -> f32;
fn perimetre(&self) -> f32 { let mut ret = 0.0; let points = self.points();
for i in 1..points.len() { ret += f32::sqrt( f32::pow(points[i].0 - points[i - 1].0, 2) + f32::pow(points[i].1 - points[i - 1].1, 2), );
return ret;
Possession et emprunt Pour obtenir des garanties de sûreté, Rust utilise les concepts d'ownership (propriété ou possession) et de borrowing (emprunt). Ainsi, une valeur a toujours un seul propriétaire. Si la valeur change de propriétaire, l'ancien propriétaire ne peut plus l'utiliser. Par exemple :fn prend_possession(v: Vec<i32>) { // Cette fonction prend possession de son paramètre v et ne la rend pas. println!("{:?}", v); }
fn main() { let mut a = vec![1, 2, 3]; // a est le propriétaire du vecteur. let mut b = a; // b est maintenant le propriétaire du vecteur.
// La valeur de a a été déplacée (move) dans b, a n'est plus utilisable. a.push(4); // erreur de compilation : a n'a plus le droit d'utiliser ce vecteur
prend_possession(b); b.push(5); // erreur de compilation : b n'a plus le droit d'utiliser ce vecteur }
Pour utiliser une valeur à plusieurs endroits à la fois, il est possible de prêter cette valeur en créant des références. Il est possible de créer :
Soit des références immuables, avec l'opérateur &. Soit une référence muable, avec l'opérateur & mut. En particulier, il n'est pas possible de mélanger les références muables et immuables. Exemple :fn take_reference(v: &Vec<i32>) { // Cette fonction prend une référence vers un vecteur println!("{:?}", v); }
fn correct() { let a = vec![1, 2, 3]; let ref_1 = &a;