Erreur Rust E0658 : use of unstable library feature (fonctionnalité instable)
E0658 veut dire : vous avez utilisé quelque chose qui existe en Rust, mais qui n’est pas encore terminé, et Rust stable refuse de vous laisser vous en servir. C’est en général une méthode trouvée dans la documentation de la bibliothèque standard ou dans un article de blog, comme .intersperse() ou .try_collect(), ou un morceau de syntaxe comme try { ... }. Votre code n’est pas faux, et rien n’est cassé sur votre machine. Vous avez simplement pris une fonctionnalité qui ne marche qu’avec le compilateur nightly. Presque à chaque fois, il existe une façon stable de faire la même chose en une ligne. Cette page fait partie du guide des erreurs du compilateur Rust.
Le message d’erreur
Section intitulée « Le message d’erreur »error[E0658]: use of unstable library feature `iter_intersperse` --> src/main.rs:3:47 |3 | let joined: String = tags.iter().copied().intersperse(", ").collect(); // ❌ méthode réservée à nightly | ^^^^^^^^^^^ | = note: see issue #79524 <https://github.com/rust-lang/rust/issues/79524> for more informationLe compilateur vous dit : « utilisation d’une fonctionnalité instable de la bibliothèque, iter_intersperse », et la note renvoie au ticket GitHub où vous trouverez plus d’informations.
Voici le programme qui la provoque :
fn main() { let tags = ["rust", "web", "cli"]; let joined: String = tags.iter().copied().intersperse(", ").collect(); // ❌ méthode réservée à nightly println!("{}", joined);}Ce que ça veut dire
Section intitulée « Ce que ça veut dire »Les ^^^^^^^^^^^ pointent intersperse à la ligne 3. Le titre donne le nom de la fonctionnalité entre accents graves, iter_intersperse. C’est le nom que l’équipe Rust donne à ce morceau inachevé de la bibliothèque standard. La note: renvoie au ticket GitHub où la fonctionnalité est discutée.
rustc a donc bien trouvé la méthode. Il sait exactement ce que vous voulez dire. Il refuse juste de la compiler, parce que intersperse est encore marquée instable (unstable) : son nom, ses arguments ou son comportement peuvent changer avant qu’elle soit terminée, ou elle peut être retirée.
D’autres formes du titre veulent dire la même chose, mais pour des fonctionnalités du langage plutôt que de la bibliothèque : the `!` type is experimental, `try` expression is experimental, ou associated type defaults are unstable.
C’est comme un magasin qui a mis un nouveau produit en rayon avec une étiquette « réservé au personnel, en test ». Vous le voyez, vous pouvez lire l’étiquette, mais la caisse refuse encore de vous le vendre.
Pourquoi Rust fait ça
Section intitulée « Pourquoi Rust fait ça »Rust fait une promesse forte : du code qui compile aujourd’hui sur Rust stable continuera de compiler sur toutes les futures versions stables de Rust 1.x. Pour tenir cette promesse, les nouvelles fonctionnalités arrivent d’abord sur le canal nightly, où les gens peuvent les essayer et où leur conception peut encore changer. Une fonctionnalité ne devient stable qu’une fois terminée, en général après des mois ou des années de tests.
Rust stable refuse tout simplement de compiler les fonctionnalités instables : vous ne pouvez donc pas bâtir sur quelque chose qui risque de bouger sous vos pieds. Si vous voulez vraiment en essayer une, nightly vous laisse l’activer par son nom avec #![feature(iter_intersperse)]. Sur stable, même cette ligne est une erreur (E0554).
La documentation de la bibliothèque standard montre les deux sortes côte à côte. Les éléments stables ont un numéro de version à droite, comme 1.82.0 : la version de Rust où ils sont devenus stables. Les éléments instables ont un encadré qui dit « 🔬 This is a nightly-only experimental API. » (API expérimentale réservée à nightly). Cet encadré est le moyen le plus rapide de repérer une E0658 avant même d’écrire du code. Voir Les outils de Rust pour comprendre comment s’articulent les canaux de Rust et rustup.
Comment corriger
Section intitulée « Comment corriger »Solution 1 : utiliser l’alternative stable
Section intitulée « Solution 1 : utiliser l’alternative stable »Choisissez-la presque à chaque fois. Les méthodes instables sont en général des raccourcis pour quelque chose que Rust stable sait déjà faire. Pour coller des chaînes avec un séparateur, join sur une slice ou un Vec fait ce que ferait intersperse(...).collect() :
fn main() { let tags = ["rust", "web", "cli"]; let joined = tags.join(", "); println!("{}", joined);
// Des chaînes produites par un itérateur : collectez-les d'abord dans un Vec, puis join. let upper: Vec<String> = tags.iter().map(|t| t.to_uppercase()).collect(); println!("{}", upper.join(" | "));}Sortie :
rust, web, cliRUST | WEB | CLISi vous préférez tout garder dans une seule chaîne d’itérateurs, la crate populaire itertools propose un join et un intersperse stables pour les itérateurs. Voir Les chaînes de caractères et Les itérateurs.
Solution 2 : chercher le badge « nightly-only » dans la documentation
Section intitulée « Solution 2 : chercher le badge « nightly-only » dans la documentation »Choisissez-la quand vous avez copié une méthode depuis la documentation, une réponse d’IA ou un article de blog. Ouvrez la méthode dans la documentation de std : si elle a l’encadré 🔬, cherchez un peu plus loin la façon stable. Un cas fréquent, c’est .try_collect() :
error[E0658]: use of unstable library feature `iterator_try_collect` --> src/main.rs:3:80 |3 | let numbers: Result<Vec<i32>, _> = inputs.iter().map(|s| s.parse::<i32>()).try_collect(); // ❌ réservé à nightly | ^^^^^^^^^^^ | = note: see issue #94047 <https://github.com/rust-lang/rust/issues/94047> for more informationMême message que plus haut, cette fois pour la fonctionnalité iterator_try_collect.
Le programme qui la provoque :
fn main() { let inputs = ["3", "14", "x"]; let numbers: Result<Vec<i32>, _> = inputs.iter().map(|s| s.parse::<i32>()).try_collect(); // ❌ réservé à nightly println!("{:?}", numbers);}Rust stable fait déjà ça avec un simple collect(). Quand les éléments sont des Result et que vous collectez dans un Result<Vec<_>, _>, vous obtenez Ok avec toutes les valeurs, ou la première Err :
use std::num::ParseIntError;
fn parse_all(inputs: &[&str]) -> Result<Vec<i32>, ParseIntError> { inputs.iter().map(|s| s.parse::<i32>()).collect()}
fn main() { println!("{:?}", parse_all(&["3", "14", "15"])); println!("{:?}", parse_all(&["3", "x", "15"]));}Sortie :
Ok([3, 14, 15])Err(ParseIntError { kind: InvalidDigit })D’autres méthodes instables que vous croiserez peut-être, avec leur voie stable : .array_chunks() sur un itérateur (iter_array_chunks ; utilisez plutôt .as_chunks() ou .chunks() sur une slice), et .map_windows() (utilisez .windows() sur une slice). Voir Result et Les slices.
Solution 3 : mettre Rust à jour si la fonctionnalité a été stabilisée récemment
Section intitulée « Solution 3 : mettre Rust à jour si la fonctionnalité a été stabilisée récemment »Choisissez-la quand la documentation montre un numéro de version au lieu de l’encadré 🔬, ou quand le même code compile chez un ami ou dans le Playground. La fonctionnalité est alors stable, simplement plus récente que votre compilateur. Par exemple, as_chunks sur les slices est devenue stable dans Rust 1.88. Avec un Rust plus ancien, vous auriez une E0658 ; avec un Rust à jour, ça marche tout simplement :
fn main() { let readings = [21, 22, 19, 20, 23]; let (pairs, rest) = readings.as_chunks::<2>(); for [a, b] in pairs { println!("{} et {}", a, b); } println!("reste : {:?}", rest);}Sortie :
21 et 2219 et 20reste : [23]Vérifiez votre version et mettez à jour :
rustc --versionrustup updateSi rustc --version affiche toujours une ancienne version ensuite, cherchez un fichier rust-toolchain.toml dans votre projet. Il fixe le projet sur une version précise de Rust, et rustup show vous dit laquelle est active. Voir Les outils de Rust.
Solution 4 : passer à nightly avec #![feature], seulement si vous le voulez vraiment
Section intitulée « Solution 4 : passer à nightly avec #![feature], seulement si vous le voulez vraiment »Choisissez-la en dernier, et seulement quand il n’existe aucune alternative stable et que vous acceptez que votre code casse avec un futur nightly. Il vous faut deux choses : une ligne #![feature(...)] en haut de main.rs (ou de lib.rs) avec le nom de fonctionnalité donné par l’erreur, et le compilateur nightly. Sur stable, la ligne #![feature] elle-même est refusée :
error[E0554]: `#![feature]` may not be used on the stable release channel --> src/main.rs:1:1 |1 | #![feature(iter_intersperse)] // ❌ permis seulement sur Rust nightly | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^rustc dit ici que #![feature] ne peut pas être utilisé sur le canal de publication stable.
Le programme, qui ne compile qu’avec nightly :
#![feature(iter_intersperse)] // ❌ permis seulement sur Rust nightly
fn main() { let tags = ["rust", "web", "cli"]; let joined: String = tags.iter().copied().intersperse(", ").collect(); println!("{}", joined);}Installez nightly à côté de votre Rust stable et utilisez-le seulement pour ce projet ou pour cette commande :
rustup toolchain install nightlycargo +nightly runSoyez honnête avec vous-même. Pour apprendre, pour des tests et pour de petits outils, nightly convient très bien. Pour une bibliothèque dont d’autres dépendent, ou pour tout ce que vous devrez maintenir, restez sur stable : la plupart des crates que vous utilisez le font aussi.
Où vous le verrez souvent
Section intitulée « Où vous le verrez souvent »Vec<i32, i32> alors que vous vouliez une liste de paires. Le second paramètre de Vec est l’allocateur de mémoire, qui est instable : la première erreur parle donc de allocator_api (quelques autres erreurs suivent) :
error[E0658]: use of unstable library feature `allocator_api` --> src/main.rs:2:26 |2 | let points: Vec<i32, i32> = vec![]; // ❌ on voulait une liste de paires (x, y) | -----^^^ | | | help: consider wrapping the inner types in tuple: `(i32, i32)`L’aide propose d’envelopper les types intérieurs dans un tuple : (i32, i32).
fn main() { let points: Vec<i32, i32> = vec![]; // ❌ on voulait une liste de paires (x, y) println!("{} points", points.len());}Correction : faites ce que dit l’aide, Vec<(i32, i32)>. Voir Les vecteurs et Les tuples. La même erreur sur Option ou Result, c’est E0107.
Le type ! dans vos propres signatures. ! veut dire « n’arrive jamais ». Il marche comme type de retour d’une fonction qui ne revient jamais, mais partout ailleurs il est encore instable :
error[E0658]: the `!` type is experimental --> src/main.rs:1:34 |1 | fn default_port() -> Result<u16, !> { // ❌ ici, le type `!` est réservé à nightly | ^rustc dit simplement que le type ! est expérimental.
fn default_port() -> Result<u16, !> { // ❌ ici, le type `!` est réservé à nightly Ok(8080)}
fn main() { println!("{:?}", default_port());}Correction : utilisez std::convert::Infallible, le type stable qui veut dire « cette erreur ne peut pas arriver », ou renvoyez simplement un u16 si rien ne peut échouer.
Les blocs try. Un bloc try { ... } permet d’utiliser ? sans écrire de fonction, mais il est réservé à nightly (`try` expression is experimental). Correction : déplacez le code dans une petite fonction qui renvoie un Result et utilisez ? là-dedans, comme dans la solution 2. Voir Result.
Proche, mais ce n’est pas E0658 : du code écrit pour l’édition 2024, comme if let Some(a) = age && a >= 18, donne let chains are only allowed in Rust 2024 or later (les chaînes de let ne sont permises qu’à partir de Rust 2024) sur une édition plus ancienne. Correction : mettez edition = "2024" dans Cargo.toml, ou imbriquez les deux if.
Erreurs liées
Section intitulée « Erreurs liées »- E0554 :
#![feature]may not be used on the stable release channel, l’erreur qui suit quand vous essayez la solution 4 sur stable. - E0599 : aucune méthode trouvée ; quand la méthode n’existe pas du tout (ou vient d’une crate que vous n’avez pas ajoutée), c’est cette erreur que vous obtenez.
- E0107 : mauvais nombre d’arguments génériques, comme
Option<i32, i32>(le cousin du casVec<i32, i32>). - E0277 : contrainte de trait non satisfaite ; une des erreurs qui suivent
Vec<i32, i32>. - E0463 : crate introuvable, si vous passez à
itertoolset oubliez de l’ajouter àCargo.toml. - Toutes les erreurs du compilateur : la liste complète des pages d’erreurs.
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. La page de documentation std d'une méthode montre un encadré « This is a nightly-only experimental API ». Que se passe-t-il si vous l'appelez sur Rust stable ?
2. .try_collect() donne E0658. Quelle est la façon stable habituelle de transformer un itérateur de Result en Result<Vec<_>, _> ?
3. Du code qui compile dans le Playground vous donne E0658 pour une méthode dont la documentation affiche 1.88.0. Que faut-il essayer d'abord ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- E0658 — Rust error codes index (en anglais) : l’explication officielle, et comment une ligne
#![feature]active une fonctionnalité sur nightly. - How Rust is Made and “Nightly Rust” — The Rust Book (en anglais) : stable, beta et nightly, le « train » des versions, et comment les fonctionnalités instables deviennent stables.
- Channels — The rustup book (en anglais) : installer nightly,
cargo +nightly, et choisir une toolchain par projet. - The Unstable Book (en anglais) : tous les noms de fonctionnalités instables que vous pouvez voir dans une E0658, avec une courte description de chacune.
slice::join— standard library docs (en anglais) : la façon stable de joindre des chaînes avec un séparateur, l’alternative àintersperse.