Aller au contenu

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.

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 information

Le 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);
}

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.

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.

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, cli
RUST | WEB | CLI
▶ Essayez par vous-même

Si 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 information

Mê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 })
▶ Essayez par vous-même

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 22
19 et 20
reste : [23]
▶ Essayez par vous-même

Vérifiez votre version et mettez à jour :

Terminal window
rustc --version
rustup update

Si 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 :

Terminal window
rustup toolchain install nightly
cargo +nightly run

Soyez 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.

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.

  • 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 cas Vec<i32, i32>).
  • E0277 : contrainte de trait non satisfaite ; une des erreurs qui suivent Vec<i32, i32>.
  • E0463 : crate introuvable, si vous passez à itertools et oubliez de l’ajouter à Cargo.toml.
  • Toutes les erreurs du compilateur : la liste complète des pages d’erreurs.

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