Rust est compilé multiparadigme, conçu par Graydon Hore alors employé chez Mozilla Research, avec la contribution du créateur de JavaScript Brendan Eich. Utilisé par plusieurs grandes entreprises et par de nombreux développeurs dans le monde, Rust est devenu le langage de base pour certaines des fonctionnalités fondamentales du navigateur Firefox et de son moteur Gecko, ainsi que pour le moteur Servo de Mozilla.
Utilisé par plusieurs grandes entreprises et par de nombreux développeurs dans le monde, Rust est devenu le langage de base pour certaines des fonctionnalités fondamentales du navigateur Firefox et de son moteur Gecko, ainsi que pour le moteur Servo de Mozilla. Le langage est également apprécié par sa communauté pour les raisons suivantes :
- performance : Rust est un langage rapide et économique en mémoire, sans environnement d'exécution, ni récupérateur mémoire, il peut dynamiser des services à hautes performances, s'exécuter dans des systèmes embarqués, et s'intégrer facilement à d'autres langages ;
- fiabilité : le système de typage et le modèle d’ownership de Rust garantissent la sécurité mémoire ainsi que la sécurité des threads. Il permet d'éliminer de nombreuses variétés de bugs dès la compilation ;
- productivité : Rust dispose d'une excellente documentation, d'un compilateur bienveillant, avec des messages d'erreur utiles. Le langage a également un gestionnaire de paquet et de compilation intégré, divers éditeurs intelligents avec autocomplétions et analyse de type. Il dispose également d’un outil de mise en forme automatique.
Passons en revue quelques améliorations de la version stable 1.66.0
Discriminants explicites sur les enum avec champs
Les enum avec des représentations entières peuvent maintenant utiliser des discriminants explicites, même s'ils ont des champs.
Code : | Sélectionner tout |
1 2 3 4 5 6 | #[repr(u8)] enum Foo { A(u8), B(i8), C(bool) = 42, } |
Auparavant, vous pouviez utiliser des discriminants explicites sur des enum avec des représentations, mais seulement si aucune de leurs variantes n'avait de champs. Les discriminants explicites sont utiles pour transmettre des valeurs au-delà des frontières linguistiques lorsque la représentation de enum doit correspondre dans les deux langues. Par exemple,
Code : | Sélectionner tout |
1 2 3 4 5 6 7 | #[repr(u8)] enum Bar { A, B, C = 42, D, } |
Ici, Bar enum est garanti pour avoir la même disposition que u8. De plus, la variante Bar::C est garantie d'avoir un discriminant de 42. Les variantes sans valeurs explicitement spécifiées auront des discriminants qui sont automatiquement assignés selon leur ordre dans le code source, ainsi Bar::A aura un discriminant de 0, Bar::B aura un discriminant de 1, et Bar::D aura un discriminant de 43. Sans cette fonctionnalité, la seule façon de définir la valeur explicite de Bar::C serait d'ajouter 41 variantes inutiles avant elle.
Note : alors que pour les enums sans champs, il est possible d'inspecter un discriminant via un casting (par exemple Bar::C as u8), Rust ne fournit aucun moyen au niveau du langage pour accéder au discriminant brut d'un enum avec des champs. Au lieu de cela, un code actuellement non sécurisé doit être utilisé pour inspecter le discriminant d'un enum avec des champs. Étant donné que cette fonctionnalité est destinée à être utilisée avec des FFI inter-langues où le code non sécurisé est déjà nécessaire. En attendant, si tout ce dont vous avez besoin est un gestionnaire opaque du discriminant, veuillez consulter la fonction std::mem::discriminant.
core::hint::black_box
Lors de l'analyse comparative ou de l'examen du code machine produit par un compilateur, il est souvent utile d'empêcher les optimisations de se produire à certains endroits. Dans l'exemple suivant, la fonction push_cap exécute Vec::push 4 fois dans une boucle :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | fn push_cap(v: &mut Vec<i32>) { for i in 0..4 { v.push(i); } } pub fn bench_push() -> Duration { let mut v = Vec::with_capacity(4); let now = Instant::now(); push_cap(&mut v); now.elapsed() } |
Si vous examinez la sortie optimisée du compilateur sur x86_64, vous remarquerez qu'elle semble plutôt courte :
example::bench_push:
sub rsp, 24
call qword ptr [rip + std::time::Instant::now@GOTPCREL]
lea rdi, [rsp + 8]
mov qword ptr [rsp + 8], rax
mov dword ptr [rsp + 16], edx
call qword ptr [rip + std::time::Instant::elapsed@GOTPCREL]
add rsp, 24
ret
En fait, toute la fonction push_cap évaluée a été optimisée. Ce problème peut être contourné en utilisant la fonction black_box nouvellement stabilisée. Fonctionnellement, black_box n'est pas très intéressante : elle prend la valeur que vous lui passez et vous la renvoie. En interne, cependant, le compilateur traite black_box comme une fonction qui peut faire n'importe quoi avec son entrée et retourner n'importe quelle valeur (comme son nom l'indique).
Ceci est très utile pour désactiver des optimisations comme celle que nous voyons ci-dessus. Par exemple, nous pouvons indiquer au compilateur que le vecteur sera effectivement utilisé pour quelque chose après chaque itération de la boucle for.
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 | use std::hint::black_box; fn push_cap(v: &mut Vec<i32>) { for i in 0..4 { v.push(i); black_box(v.as_ptr()); } } |
mov dword ptr [rbx], 0
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 4], 1
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 8], 2
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 12], 3
mov qword ptr [rsp + 8], rbx
Il est également possible de voir un effet latent de l'appel à black_box dans cette sortie assembleur. L'instruction mov qword ptr [rsp + 8], rbx est répétée inutilement après chaque itération. Cette instruction écrit l'adresse v.as_ptr() comme premier argument de la fonction, qui n'est jamais réellement appelée.
Remarquez que le code généré n'est pas du tout concerné par la possibilité d'allocations introduites par l'appel push. Ceci est dû au fait que le compilateur utilise toujours le fait que nous avons appelé Vec::with_capacity(4) dans la fonction bench_push. Vous pouvez jouer avec le placement de black_box, ou essayer de l'utiliser à plusieurs endroits, pour voir ses effets sur les optimisations du compilateur.
cargo remove pour supprimer les dépendances
D'après l'équipe Rust, la gestion des dépendances est un problème difficile, et l'une des parties les plus difficiles est de choisir la version d'une dépendance à utiliser lorsqu'elle est dépendante de deux paquets différents. Cela ne comprend pas seulement son numéro de version, mais aussi les fonctionnalités qui sont ou ne sont pas activées pour le paquet. Le comportement par défaut de Cargo consiste à fusionner les fonctionnalités d'un seul paquet lorsqu'il est mentionné plusieurs fois dans le graphe des dépendances.
Par exemple, lorsque que vous avez une dépendance appelée foo avec les fonctionnalités A et B, qui est utilisée par les paquets bar et baz, mais bar dépend de foo+A et baz dépend de foo+B. Cargo fusionnera ces deux fonctionnalités et compilera [C=Rust]foo[C] comme foo+AB. L'avantage est que vous n'avez à compiler foo qu'une seule fois, et qu'il peut ensuite être réutilisé pour bar et baz. Cependant, cela comporte aussi un inconvénient. Que faire si une fonctionnalité activée dans une dépendance de construction n'est pas compatible avec la cible pour laquelle vous construisez ?
Un exemple commun de ceci dans l'écosystème est la fonctionnalité optionnelle std incluse dans beaucoup de crates #![no_std], qui permet aux crates de fournir des fonctionnalités supplémentaires lorsque std est disponible. Imaginez maintenant que vous voulez utiliser la version #![no_std] de foo dans votre binaire #![no_std], et utiliser foo au moment de la construction dans votre build.rs. Si votre dépendance au moment de la construction dépend de foo+std, votre binaire dépend maintenant aussi de foo+std, ce qui signifie qu'il ne compilera plus, car std n'est pas disponible pour votre plateforme cible.
C'est un problème de longue date dans Cargo, la version 1.51 apportait une nouvelle option resolver dans Cargo.toml, où il est possible de définir resolver="2" pour dire à Cargo d'essayer une nouvelle approche pour résoudre les fonctionnalités. Dans Rust 1.62.0 l'équipe Rust a introduit cargo add, un utilitaire en ligne de commande pour ajouter des dépendances aux projets Rust. Maintenant, il est possible d'utiliser cargo remove pour supprimer les dépendances.
Rust un langage de programmation très apprécié des BigTech
Rust est l’un des langages de programmation les plus appréciés et dont la croissance est la plus rapide à l'heure actuelle. Selon Google, les défauts de sécurité de la mémoire menacent fréquemment la sécurité des appareils, en particulier pour les applications et les systèmes d'exploitation. Par exemple, sur le système d'exploitation mobile Android, Google dit avoir constaté que plus de la moitié des vulnérabilités de sécurité traitées en 2019 résultaient de bogues de sécurité de la mémoire. Rust s'est avéré efficace pour fournir une couche de protection supplémentaire au-delà même de ces outils dans de nombreux autres projets, y compris les navigateurs, les jeux et même les bibliothèques clés.
AWS utilise Rust pour fournir des services tels qu'Amazon Simple Storage Service (Amazon S3), Amazon Elastic Compute Cloud (Amazon EC2), Amazon CloudFront, et plus encore. Récemment, l’entreprise a lancé Bottlerocket, un système d'exploitation basé sur Linux et écrit en Rust. L’équipe Amazon EC2 utilise le langage Rust pour développer les nouveaux composants du système Nitro d'AWS, y compris les applications sensibles, telles que les enclaves Nitro.
Microsoft a récemment formé une équipe Rust pour contribuer aux efforts d'ingénierie de l'écosystème du langage. L’entreprise spécialisée dans le développement de logiciel prévoit de travailler avec la communauté Rust sur le compilateur, les outils de base, la documentation et bien plus. Selon Nell Shamrell Harrington, Ingénieur logiciel chez Microsoft et directeur du conseil d'administration de la Fondation Rust, les logiciels et les langages open source sont d'une importance capitale pour son entreprise et pour l'ensemble de l'industrie technologique. « Au fur et à mesure que l'utilisation de Rust se développe chez Microsoft, nous savons qu'il ne suffit pas de l'utiliser uniquement comme logiciel open source. Nous devons également y contribuer », a-t-il déclaré sur le billet de blog publié ce 8 février par Microsoft. « Rejoindre la Fondation Rust est une façon pour nous de soutenir financièrement le projet et de nous engager plus profondément avec la communauté Rust », précise Harrington.
Facebook a adopté Rust depuis 2016 et l'utilise dans tous les aspects du développement. En février, AWS, Huawei, Google, Microsoft et Mozilla se sont associées pour lancer la fondation Rust et se sont engagées à lui consacrer un budget de deux ans à hauteur d'un million de dollars. « Ce budget permettra au projet de développer des services, des programmes et des événements qui aideront les responsables du projet Rust à développer le meilleur Rust possible », ont-ils souligné.
Lors d’une conférence d’AWS tenue cette année, Shane Miller, présidente de la Fondation Rust, et Carl Lerche, chef de projet de Tokio, ont plaidé en faveur de l'utilisation de Rust pour minimiser l'impact environnemental, tout en précisant que sa courbe d'apprentissage abrupte rendait la tâche difficile. Un composant JavaScript a été réécrit en Rust et aurait obtenu une amélioration de 50 % de la latence, une réduction de 75 % de l'utilisation du CPU et une réduction de 95 % de l'utilisation de la mémoire. « C'est assez fou, a déclaré Miller. C'est une économie substantielle, pas seulement dans l'infrastructure, cela se traduit par des économies d'énergie. »
Si vous avez une version précédente de Rust installée via rustup, il est possible d'obtenir la 1.66.0 avec :
$ rustup update stable
Source : Rust
Et vous ?
Que pensez-vous des nouveautés de Rust 1.66.0 ?
Quel est votre avis sur l'utilitaire cargo remove pour supprimer les dépendances ?
Voir aussi :
Rust peut-il sauver la planète ? Un composant JavaScript a été réécrit en Rust et aurait une amélioration de 50 % de la latence, une réduction de 75 % de l'utilisation du CPU et 95 % de la mémoire
Rust 1.51 est disponible avec Resolver, une nouvelle fonctionnalité pour Cargo et l'implémentation MVP des const generics
Facebook rejoint AWS, Huawei, Google, Microsoft et Mozilla dans la Fondation Rust, et renforce son équipe Rust par des nouveaux talents