Errore Rust E0658: use of unstable library feature (funzionalità sperimentale)
E0658 significa: hai usato qualcosa che in Rust esiste, ma non è ancora finito, quindi Rust stabile non ti lascia usarlo. Di solito è un metodo che hai trovato nella documentazione della libreria standard o in un articolo, come .intersperse() o .try_collect(), oppure un pezzo di sintassi come try { ... }. Il tuo codice non è sbagliato, e sulla tua macchina non c’è niente di rotto. Hai solo preso una funzionalità che funziona soltanto con il compilatore nightly. Quasi sempre esiste un modo stabile per fare la stessa cosa in una riga. (Questa pagina fa parte di Errori del compilatore Rust spiegati.)
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”error[E0658]: use of unstable library feature `iter_intersperse` --> src/main.rs:3:47 |3 | let joined: String = tags.iter().copied().intersperse(", ").collect(); // ❌ nightly-only method | ^^^^^^^^^^^ | = note: see issue #79524 <https://github.com/rust-lang/rust/issues/79524> for more informationIl compilatore dice: stai usando la funzionalità instabile della libreria iter_intersperse. Questo è il programma che produce l’errore:
fn main() { let tags = ["rust", "web", "cli"]; let joined: String = tags.iter().copied().intersperse(", ").collect(); // ❌ nightly-only method println!("{}", joined);}Cosa significa
Sezione intitolata “Cosa significa”Il ^^^^^^^^^^^ indica intersperse alla riga 3. La prima riga riporta tra apici inversi il nome della funzionalità, iter_intersperse. È il nome che il team di Rust usa per questo pezzo non ancora finito della libreria standard. La note: rimanda alla issue su GitHub in cui se ne discute.
Quindi rustc ha trovato il metodo. Sa esattamente che cosa intendi. Solo che non lo compila, perché intersperse è ancora segnato come instabile: prima di essere finito potrebbe cambiare nome, argomenti o comportamento, o potrebbe venire rimosso.
Altre forme della prima riga significano la stessa cosa per funzionalità del linguaggio invece che della libreria: the `!` type is experimental, `try` expression is experimental, oppure associated type defaults are unstable.
È come un negozio che ha un prodotto nuovo sullo scaffale con un adesivo «solo personale, ancora in prova». Lo vedi, puoi leggere l’etichetta, ma la cassa non te lo vende ancora.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”Rust fa una promessa forte: il codice che oggi compila con Rust stabile continua a compilare con ogni futura versione stabile 1.x. Per mantenere questa promessa, le nuove funzionalità arrivano prima sul canale nightly, dove le persone possono provarle e il design può ancora cambiare. Solo quando una funzionalità è pronta diventa stabile, di solito dopo mesi o anni di prove.
Rust stabile si rifiuta del tutto di compilare le funzionalità instabili, così non puoi costruire su qualcosa che potrebbe cambiarti sotto i piedi. Se vuoi davvero provarne una, nightly ti permette di attivarla per nome con #![feature(iter_intersperse)]. Su stabile, anche quella riga è un errore (E0554).
La documentazione della libreria standard mostra i due tipi uno accanto all’altro. Gli elementi stabili hanno un numero di versione a destra, come 1.82.0: la versione di Rust in cui sono diventati stabili. Quelli instabili hanno un riquadro che dice «🔬 This is a nightly-only experimental API.» Quel riquadro è il modo più veloce per accorgerti di un E0658 prima ancora di scrivere codice. Vedi Strumenti Rust e installazione per capire come stanno insieme i canali di Rust e rustup.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: usa l’alternativa stabile
Sezione intitolata “Soluzione 1: usa l’alternativa stabile”Scegli questa quasi sempre. I metodi instabili di solito sono scorciatoie per qualcosa che Rust stabile sa già fare. Per unire delle stringhe con un separatore, join su una slice o su un Vec fa quello che farebbe intersperse(...).collect():
fn main() { let tags = ["rust", "web", "cli"]; let joined = tags.join(", "); println!("{}", joined);
// Stringhe prodotte da un iteratore: prima raccoglile in un Vec, poi usa join. let upper: Vec<String> = tags.iter().map(|t| t.to_uppercase()).collect(); println!("{}", upper.join(" | "));}Output:
rust, web, cliRUST | WEB | CLISe preferisci tenere tutto in un’unica catena di iteratori, il diffuso crate itertools ha join e intersperse stabili per gli iteratori. Vedi Stringhe in Rust e Iteratori in Rust.
Soluzione 2: controlla nella documentazione il riquadro «nightly-only»
Sezione intitolata “Soluzione 2: controlla nella documentazione il riquadro «nightly-only»”Scegli questa quando hai copiato un metodo dalla documentazione, da una risposta di un’IA o da un articolo. Apri il metodo nella documentazione di std: se ha il riquadro 🔬, cerca un po’ più in là la strada stabile. Uno frequente è .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(); // ❌ nightly-only | ^^^^^^^^^^^ | = note: see issue #94047 <https://github.com/rust-lang/rust/issues/94047> for more informationIl programma che non compila:
fn main() { let inputs = ["3", "14", "x"]; let numbers: Result<Vec<i32>, _> = inputs.iter().map(|s| s.parse::<i32>()).try_collect(); // ❌ nightly-only println!("{:?}", numbers);}Rust stabile lo fa già con un semplice collect(). Quando gli elementi sono Result e li raccogli in un Result<Vec<_>, _>, ottieni Ok con tutti i valori, oppure il primo 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"]));}Output:
Ok([3, 14, 15])Err(ParseIntError { kind: InvalidDigit })Altri metodi instabili in cui potresti imbatterti, con la strada stabile: .array_chunks() su un iteratore (iter_array_chunks; usa invece .as_chunks() o .chunks() su una slice), e .map_windows() (usa .windows() su una slice). Vedi Result in Rust e Slice in Rust.
Soluzione 3: aggiorna Rust se la funzionalità è stata stabilizzata da poco
Sezione intitolata “Soluzione 3: aggiorna Rust se la funzionalità è stata stabilizzata da poco”Scegli questa quando la documentazione mostra un numero di versione invece del riquadro 🔬, oppure lo stesso codice compila a un amico o sul Playground. Allora la funzionalità è stabile, solo più recente del tuo compilatore. Per esempio, as_chunks sulle slice è diventato stabile in Rust 1.88. Con un Rust più vecchio otterresti E0658; con uno aggiornato funziona e basta:
fn main() { let readings = [21, 22, 19, 20, 23]; let (pairs, rest) = readings.as_chunks::<2>(); for [a, b] in pairs { println!("{} e {}", a, b); } println!("avanzo: {:?}", rest);}Output:
21 e 2219 e 20avanzo: [23]Controlla la tua versione e aggiorna:
rustc --versionrustup updateSe dopo rustc --version mostra ancora una versione vecchia, cerca un file rust-toolchain.toml nel tuo progetto. Blocca il progetto su una versione di Rust, e rustup show ti dice quale è attiva. Vedi Strumenti Rust e installazione.
Soluzione 4: passa a nightly con #![feature], solo se lo vuoi davvero
Sezione intitolata “Soluzione 4: passa a nightly con #![feature], solo se lo vuoi davvero”Scegli questa per ultima, e solo quando non c’è un’alternativa stabile e ti sta bene che il codice si rompa con un futuro nightly. Ti servono due cose: una riga #![feature(...)] in cima a main.rs (o lib.rs) con il nome della funzionalità preso dall’errore, e il compilatore nightly. Su stabile viene rifiutata la riga #![feature] stessa:
error[E0554]: `#![feature]` may not be used on the stable release channel --> src/main.rs:1:1 |1 | #![feature(iter_intersperse)] // ❌ only allowed on nightly Rust | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Il programma, che compila solo su nightly:
#![feature(iter_intersperse)] // ❌ only allowed on nightly Rust
fn main() { let tags = ["rust", "web", "cli"]; let joined: String = tags.iter().copied().intersperse(", ").collect(); println!("{}", joined);}Installa nightly accanto al tuo Rust stabile e usalo solo per questo progetto o per questo comando:
rustup toolchain install nightlycargo +nightly runQui sii onesto con te stesso. Per imparare, per i test e per piccoli strumenti, nightly va benissimo. Per una libreria da cui dipendono altre persone, o per qualsiasi cosa che devi mantenere, resta su stabile: lo fa anche la maggior parte dei crate che usi.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Vec<i32, i32> quando intendevi una lista di coppie. Il secondo parametro di Vec è l’allocatore di memoria, che è instabile, quindi il primo errore riguarda allocator_api (e ne seguono altri):
error[E0658]: use of unstable library feature `allocator_api` --> src/main.rs:2:26 |2 | let points: Vec<i32, i32> = vec![]; // ❌ meant a list of (x, y) pairs | -----^^^ | | | help: consider wrapping the inner types in tuple: `(i32, i32)`fn main() { let points: Vec<i32, i32> = vec![]; // ❌ meant a list of (x, y) pairs println!("{} points", points.len());}Correzione: fai quello che dice l’help, Vec<(i32, i32)>. Vedi Vettori in Rust e Tuple in Rust. Lo stesso sbaglio su Option o Result è E0107.
Il tipo ! nelle tue firme. ! significa «non succede mai». Funziona come tipo di ritorno di una funzione che non ritorna mai, ma in qualsiasi altro punto è ancora instabile:
error[E0658]: the `!` type is experimental --> src/main.rs:1:34 |1 | fn default_port() -> Result<u16, !> { // ❌ the `!` type is nightly-only here | ^fn default_port() -> Result<u16, !> { // ❌ the `!` type is nightly-only here Ok(8080)}
fn main() { println!("{:?}", default_port());}Correzione: usa std::convert::Infallible, il tipo stabile per dire «questo errore non può succedere», oppure restituisci semplicemente u16 se niente può fallire.
I blocchi try. Un blocco try { ... } ti permette di usare ? senza scrivere una funzione, ma funziona solo su nightly (`try` expression is experimental). Correzione: sposta il codice in una piccola funzione che restituisce Result e usa ? lì, come nella soluzione 2. Vedi Result in Rust.
Collegato, ma non E0658: il codice scritto per l’edizione 2024, come if let Some(a) = age && a >= 18, su un’edizione più vecchia dà let chains are only allowed in Rust 2024 or later. Correzione: imposta edition = "2024" in Cargo.toml, oppure annida i due if.
Errori correlati
Sezione intitolata “Errori correlati”- E0554:
#![feature]may not be used on the stable release channel, l’errore che arriva se provi la soluzione 4 su stabile. - E0599: metodo non trovato; quando il metodo non esiste proprio (o viene da un crate che non hai aggiunto), ottieni questo.
- E0107: numero sbagliato di argomenti generici, come
Option<i32, i32>(il cugino del casoVec<i32, i32>). - E0277: vincolo di trait non soddisfatto; uno degli errori che seguono
Vec<i32, i32>. - E0463: crate non trovato, se passi a
itertoolse ti dimentichi di aggiungerlo aCargo.toml. - Tutti gli errori del compilatore: l’elenco completo delle pagine sugli errori.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. La pagina della documentazione di std per un metodo mostra un riquadro con scritto "This is a nightly-only experimental API". Che cosa succede se lo chiami con Rust stabile?
2. .try_collect() dà E0658. Qual è il modo stabile abituale per trasformare un iteratore di Result in Result<Vec<_>, _>?
3. Del codice che compila sul Playground ti dà E0658 per un metodo la cui documentazione mostra 1.88.0. Che cosa provi per prima cosa?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0658 — Rust error codes index (in inglese): la spiegazione ufficiale, e come una riga
#![feature]attiva una funzionalità su nightly. - How Rust is Made and “Nightly Rust” — The Rust Book (in inglese): stable, beta e nightly, il «release train», e come le funzionalità instabili diventano stabili.
- Channels — The rustup book (in inglese): installare nightly,
cargo +nightly, e impostare una toolchain per progetto. - The Unstable Book (in inglese): ogni nome di funzionalità instabile che puoi vedere in un E0658, con una breve descrizione.
slice::join— documentazione della libreria standard (in inglese): il modo stabile per unire stringhe con un separatore, l’alternativa aintersperse.