IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

La version 1.96.0 du langage de programmation Rust est disponible, apportant de nouveaux types Range*, de nouvelles macros stabilisées et des corrections de vulnérabilités dans Cargo

Le , par Jade Emy

25PARTAGES

5  0 
La version 1.96.0 du langage de programmation Rust est disponible, apportant de nouveaux types Range*, de nouvelles macros stabilisées et des corrections de vulnérabilités dans Cargo

La version 1.96.0 du langage Rust introduit de nouveaux types core::range compatibles avec Copy, permettant d'utiliser des plages dans les structs Copy et d'exposer des champs publics dans RangeInclusive. Cette version stabilise également les macros assert_matches! et debug_assert_matches!, qui améliorent les diagnostics de correspondance de motifs, bien qu'elles nécessitent une importation manuelle.

Rust est un langage de programmation polyvalent qui met l'accent sur les performances, la sécurité des types, la concurrence et la sécurité de la mémoire. Rust prend en charge plusieurs paradigmes de programmation. Il s'inspire de concepts issus de la programmation fonctionnelle, notamment l'immuabilité, les fonctions d'ordre supérieur, les types de données algébriques et la correspondance de motifs. Il prend également en charge la programmation orientée objet via des structures, des énumérations, des traits et des méthodes. Rust garantit la sécurité de la mémoire (c'est-à-dire que toutes les références pointent vers une mémoire valide) sans recourir à un ramasse-miettes classique ; à la place, les erreurs de sécurité de la mémoire et les conflits d'accès sont évités par le « vérificateur d'emprunt », qui suit la durée de vie des objets référencés lors de la compilation.

La version 1.96.0 du langage Rust introduit de nouveaux types core::range compatibles avec Copy, permettant d'utiliser des plages dans les structs Copy et d'exposer des champs publics dans RangeInclusive. Cette version stabilise également les macros assert_matches! et debug_assert_matches!, qui améliorent les diagnostics de correspondance de motifs, bien qu'elles nécessitent une importation manuelle. Les cibles WebAssembly traitent désormais les symboles de l'éditeur de liens non définis comme des erreurs par défaut. Deux vulnérabilités de Cargo affectant les registres tiers sont également corrigées.


Voici les nouveautés de la version stable 1.96.0 :

Nouveaux types Range*.

De nombreux utilisateurs s'attendent à ce que Range et les types core::ops associés soient de type Copy, mais ce n'est pas le cas : ils implémentent directement Iterator, et il serait risqué d'implémenter à la fois Iterator et Copy sur le même type, ce qui a donc été évité. La RFC3550 proposait un ensemble de types Range de remplacement qui implémentent IntoIterator plutôt qu'Iterator, ce qui signifie qu'ils peuvent également être de type Copy. La partie de cette RFC concernant la bibliothèque standard est désormais stable, introduisant :

- core::range::Range,
- core::range::RangeFrom,
- core::range::RangeInclusive.
- Itérateurs associés

Une version de Rust à venir ajoutera également core::range::RangeFull et core::range::RangeTo en tant que réexportations depuis core::ops (ces derniers n'implémentent pas Iterator et implémentent déjà Copy), ainsi que core::range::legacy::* en tant que nouvel emplacement pour les plages actuelles. La syntaxe de plage telle que 0..1 produit encore les types hérités pour l'instant, mais sera mise à jour vers les types core::range dans une future édition.

Grâce à ces stabilisations, il est désormais possible de stocker des accesseurs de tranche dans des types Copy sans séparer start et end :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
use core::range::Range;
 
#[derive(Clone, Copy)]
pub struct Span(Range<usize>);
 
impl Span {
    pub fn of(self, s: &str) -> &str {
        &s[self.0]
    }
}


Le nouveau RangeInclusive rend également ses champs publics, contrairement à l'ancienne version qui évitait d'exposer l'état d'itérateur épuisé. Cela ne pose pas de problème avec le nouveau type, car celui-ci doit être converti pour pouvoir commencer l'itération.

Les auteurs de bibliothèques devraient envisager d'utiliser impl RangeBounds dans leur API publique, qui accepte à la fois les anciens types de plage et les nouveaux. Si un type concret est nécessaire, privilégiez l'utilisation des nouvelles plages, car celles-ci finiront par devenir la norme.

Assertions de correspondance de motifs

Les nouvelles macros assert_matches! et debug_assert_matches! vérifient qu’une valeur correspond à un motif donné, et déclenchent une panique avec une représentation Debug de la valeur dans le cas contraire. Elles sont essentiellement identiques à assert!(matches!(..)) et debug_assert!(matches!(..)), mais la valeur affichée améliore les chances de diagnostiquer l’échec.

Ces nouvelles macros n’ont pas été ajoutées au prélude standard, car elles entreraient en conflit avec des crates tierces populaires fournissant des macros du même nom. Elles doivent donc être importées manuellement depuis core ou std avant utilisation.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
use core::assert_matches;
 
/// [Random Number](https://xkcd.com/221/)
fn get_random_number() -> u32 {
    // chosen by a fair dice roll.
    // guaranteed to be random.
    4
}
 
fn main() {
    assert_matches!(get_random_number(), 1..=6);
}


Modifications apportées aux cibles WebAssembly

Les cibles WebAssembly ne transmettent plus l'option --allow-undefined à l'éditeur de liens, ce qui signifie que les symboles non définis lors de la liaison génèrent désormais une erreur d'éditeur de liens au lieu d'être convertis en importations WebAssembly à partir du module "env". Cette modification empêche la liaison des modules tant que tous les symboles liés à la liaison ne sont pas définis, afin de détecter les bogues plus tôt et d'éviter les problèmes accidentels liés à la dénomination des symboles ou autres.

Les symboles liés à la liaison non définis sont souvent le signe de bogues liés à la compilation ou d’une mauvaise configuration. Si, toutefois, l’ancien comportement est souhaité, il peut être réactivé avec RUSTFLAGS=-Clink-arg=--allow-undefined ou en modifiant le code source et en utilisant #[link(wasm_import_module = « env »)] sur le bloc définissant le symbole.

Ce changement avait été annoncé précédemment et prend désormais effet dans Rust 1.96.

Deux avis de sécurité concernant Cargo

Rust 1.96 contient des correctifs pour deux vulnérabilités affectant les utilisateurs de registres tiers.

- CVE-2026-5223 est une vulnérabilité de gravité moyenne concernant l'extraction d'archives de crates contenant des liens symboliques.
- CVE-2026-5222 est une vulnérabilité de gravité faible concernant l'authentification avec des URL normalisées.

Les utilisateurs de crates.io ne sont affectés par aucune de ces vulnérabilités.

Source : Annonce de Rust 1.96.0

Et vous ?

Pensez-vous que cette version est crédible ou pertinente ?
Quel est votre avis sur le sujet ?

Voir aussi :

Rust a-t-il atteint son plafond de popularité ? Le langage recule de trois places dans l'index TIOBE d'avril 2026. Son PDG évoque une « courbe d'apprentissage difficile pour les développeurs non experts »

Submergé par les bugs dans ses applications, la solution de Microsoft c'est de supprimer tout le code C et C++ de ses référentiels d'ici 2030, pour le remplacer par Rust

« Rust sauvera Linux de l'IA », affirme Greg Kroah-Hartman dans le cadre d'une critique de l'usage de l'intelligence artificielle pour trouver les bogues au sein du code du noyau écrit en langage C
Vous avez lu gratuitement 2 648 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de fdecode
Membre habitué https://www.developpez.com
Le 02/06/2026 à 12:50
Citation Envoyé par OuftiBoy Voir le message
Je vois que Rust introduit le type "Range", c'est exactement (si j'ai bien compris l'article),
Bonjour OuftiBoy!

Les ranges existent depuis longtemps. Déjà présent dans la version 1.0 de 2015.

Là il s'agit d'une version alternative qui permet la copie. On dirait que ces versions remplaceront les anciennes pour certaines fonctionnalités, mais quoiqu'il en soit, ces nouveaux range ne sont pas des itérateurs, mais peuvent être transformés en itérateurs (la différence entre implémenter le trait 'Iterator' ou implémenter le trait 'IntoIterator').

Et bon courage pour ton langage.
1  0 
Avatar de fdecode
Membre habitué https://www.developpez.com
Le 04/06/2026 à 9:06
Citation Envoyé par Uther Voir le message
En effet la notion de range dans ton langage, de ce que j'en est compris est plus proche des range d'Ada : une limitation définie à la compilation des valeurs possible sur un type.
Les range en Rust sont juste des types normaux (struct) qui représentant un intervalle. mais sans grand chose de particulier à part une écriture abrégée.
On peut faire des ranged type maison en Rust [playground]:
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RangedI128<const MIN: i128, const MAX: i128>(i128);
 
impl<const MIN: i128, const MAX: i128> RangedI128<MIN, MAX> {
    const _ASSERT_BOUNDS: () = assert!(MAX >= MIN);
 
    pub const fn try_new(x: i128) -> Option<Self> {
        let _ = Self::_ASSERT_BOUNDS;
        if x < MIN || x > MAX {
            None
        } else {
            Some(Self(x))
        }
    }
 
    pub const fn get(self) -> i128 {
        self.0
    }
}
Ça pourrait être un peu mieux, mais on est limité par les capacités actuelles des génériques constants.
1  0 
Avatar de OuftiBoy
Membre éprouvé https://www.developpez.com
Le 03/06/2026 à 16:39
fdecode,

Citation Envoyé par fdecode Voir le message
Les ranges existent depuis longtemps. Déjà présent dans la version 1.0 de 2015.

Là il s'agit d'une version alternative qui permet la copie. On dirait que ces versions remplaceront les anciennes pour certaines fonctionnalités, mais quoiqu'il en soit, ces nouveaux range ne sont pas des itérateurs, mais peuvent être transformés en itérateurs (la différence entre implémenter le trait 'Iterator' ou implémenter le trait 'IntoIterator').
Je n'avais pas vu cela, je m'étais attardé plus sur la protection mémoire. Mais a y regarder de plus près, ce que je fais est plus "basic". Mes "ranges" permettent de ne jamais pouvoir déborder d'un tableau (à la compilation), et d'éviter des type 'underflow' ou 'overflow' (à la compilation). Le compilateur 'trace' chaque utilisation des variables, quelle qu'elles soient, et émet une erreur si un 'risque' existe. Pour que la vérification se fasse dès compilation, le compilateur 'connait' ce que l'on peut encore 'retirer' ou 'ajouter' à une variable. C'est très précis avec des constantes, et un peut moins si ne connait que le max d'une variable. C'est pour ça que je n'utilise pas les 'types machine', remplacés par mes 'ranges' dont on peut définir la plage très précisément.

Lors de la génération de l'IRC j'utilise évidemment des 'types' machine, mais le compilateur a valider les 'bornes' de chaque variable avant.

Citation Envoyé par fdecode Voir le message
Et bon courage pour ton langage.


J'avance bien, j'alterne entre faire avancer le compilateur, le langage, et la doc (qui prend vite du temps).

BàT et Peace & Love.
0  0 
Avatar de Uther
Expert éminent sénior https://www.developpez.com
Le 04/06/2026 à 8:30
En effet la notion de range dans ton langage, de ce que j'en est compris est plus proche des range d'Ada : une limitation définie à la compilation des valeurs possible sur un type.
Les range en Rust sont juste des types normaux (struct) qui représentant un intervalle. mais sans grand chose de particulier à part une écriture abrégée.
0  0 
Avatar de Uther
Expert éminent sénior https://www.developpez.com
Le 04/06/2026 à 14:16
En effet j'avais fait quelques essais de type entier bornés par des const génériques, mais on finit vite par tomber sur des limites, y compris en activant certaines parties encore expérimentales du support des const génériques.
0  0 
Avatar de fdecode
Membre habitué https://www.developpez.com
Le 04/06/2026 à 16:42
Citation Envoyé par Uther Voir le message
En effet j'avais fait quelques essais, mais on finit vite par tomber sur des limites, y compris en activant certaines parties encore expérimentales du support des const génériques.
Par exemple, il n'y a pas d'arithmétique sur les const génériques en stable pour l'instant.

Ceci étant dit, le crate typenum:
https://crates.io/crates/typenum/
est une jolie application des capacités des traits Rust pour définir des types à signification numérique (et en binaire).
Un exemple [playground]:
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
use std::ops::{ Mul, Sub};
 
#[macro_use] extern crate typenum;
use typenum::{ Unsigned, Integer, Sub1, Prod, Bit, UInt, consts::* };
 
// deux calculs de type numérique
type X0 = op!(pow(P3,P4) + P3 * (P2 - N2));
type X1 = op!(P1 + P2 * (P2 - N2));
 
type Result0 = op!(P93 == X0);
type Result1 = op!(P8 == X1);
 
/// Calcul statique de la factoriel d'un type numérique non signé
trait Factorial {
    type F;
}
/// Shortcut
type Fact<U> = <U as Factorial>::F;
// initialisation
impl Factorial for U0 {
    type F = U1;
}
// récursion
impl<U: Unsigned, B: Bit> Factorial for UInt<U, B> where UInt<U, B>: Sub<B1>, 
       Sub1<UInt<U, B>>: Factorial, UInt<U, B> : Mul< Fact<Sub1<UInt<U, B>>> > {
    type F = Prod<UInt<U, B>, Fact<Sub1<UInt<U, B>>> >;
}
 
/// Factorielle de 20
type F20 = Fact<U20>;
 
fn main() {
    println!("X0 -> {}", X0::to_i64());
    println!("X1 -> {}", X1::to_i64());
    println!("Result0 -> {}", Result0::to_bool());
    println!("Result1 -> {}", Result1::to_bool());
    println!("20! = {}\n", F20::to_i64());
}
Bien entendu, cet exemple d'implémentation de la factorielle en typenum est plus complexe qu'un calcul de factorielle par template en C++.
Mais il faut noter que l'arithmétique des constantes génériques n'est pas stabilisée en Rust pour l'instant.
Il s'agit d'une méthode de contournement, qu'autorise le système de typage de Rust. Et les arcanes des traits et du conditionnement de types requièrent une certaine expérience.

Mais c'est grâce à typenum que, par exemple, nalgebra peut implémenter du calcul matriciel avec contrôle de compatibilité dimensionnelle au niveau du typage (pour les matrices de shape statique).

Quand on débute en Rust on comprend vite que le langage est bas niveau et est sécurisé en mémoire, mais on n'imagine pas forcément ce que permet son système de type.
0  0 
Avatar de Uther
Expert éminent sénior https://www.developpez.com
Le 04/06/2026 à 17:33
Typenum, c'est quand même un hack du système de type. C'est peut-être acceptable pour des petites valeurs comme le nombre de dimensions, mais pour les types numérique qu'on utilise partout, c'est vraiment trop de bricolage.
0  0 
Avatar de fdecode
Membre habitué https://www.developpez.com
Le 04/06/2026 à 17:40
Citation Envoyé par Uther Voir le message
Typenum, c'est quand même un hack du système de type. C'est peut-être acceptable pour des petites valeurs comme le nombre de dimensions
C'est un hack, oui. Mais c'est un hack binaire: le type U20 est obtenu par un assemblage de types B0 et B1.
Donc on a une complexité qui est réduite logarithmiquement par le codage binaire.

Dans cet exemple, tu vois bien que le type F20 que j'ai défini (factorielle de 20) est un entier plutôt grand.

Mais je suis d'accord, cela ne remplacera pas une véritable arithmétique des génériques constants. C'est une belle performance de codage par contre, je trouve.

Citation Envoyé par Uther Voir le message
pour les types numérique qu'on utilise partout, c'est vraiment trop de bricolage.
C'est propre et ça marche plutôt bien.
0  0 
Avatar de Uther
Expert éminent sénior https://www.developpez.com
Le 05/06/2026 à 2:58
Je suis d'accord que c'est un très belle performance, mais je ne conseillerais pas ça pour quelque chose d'aussi central que le remplacement des types numériques de base, a moins d'avoir un besoin très fort sur ce sujet.
  • Ca ajoute un style de codage supplémentaire
  • Ca a probablement un impact substantiel sur les performances de compilation. Même si l'impact de la taille des nombre est logarithmique, le moindre nombre traité va nécessiter la combinaison de plusieurs types.
  • Ca a aussi un impact sur la lisibilité des messages d'erreur, si je me souviens bien (la dernière fois que j'ai joué avec typenum date un peu.)
0  0 
Avatar de fdecode
Membre habitué https://www.developpez.com
Le 05/06/2026 à 10:07
Citation Envoyé par Uther Voir le message
je ne conseillerais pas ça pour quelque chose d'aussi central que le remplacement des types numériques de base, a moins d'avoir un besoin très fort sur ce sujet.
Bien entendu!
0  0