Ошибка Rust E0658: use of unstable library feature (нестабильная возможность)
E0658 значит: ты использовал то, что в Rust уже есть, но ещё не доделано, поэтому стабильный Rust не даёт этим пользоваться. Обычно это метод, который ты нашёл в документации стандартной библиотеки или в статье, например .intersperse() или .try_collect(), либо конструкция языка вроде try { ... }. Твой код не ошибочный, и на твоём компьютере ничего не сломано. Ты просто потянулся к возможности, которая работает только в компиляторе nightly. Почти всегда есть стабильный способ сделать то же самое одной строкой. (Эта страница входит в раздел Ошибки компилятора Rust с объяснениями.)
Сообщение об ошибке
Заголовок раздела «Сообщение об ошибке»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 informationПо-русски: «использование нестабильной возможности библиотеки iter_intersperse». В заметке rustc даёт ссылку на обсуждение этой возможности на GitHub.
Вот программа, которая её вызывает (комментарий // ❌ оставлен на английском, потому что rustc цитирует эту строку; он значит «метод только для nightly»):
fn main() { let tags = ["rust", "web", "cli"]; let joined: String = tags.iter().copied().intersperse(", ").collect(); // ❌ nightly-only method println!("{}", joined);}Что это значит
Заголовок раздела «Что это значит»^^^^^^^^^^^ указывает на intersperse в строке 3. Заголовок даёт имя возможности в обратных кавычках: iter_intersperse. Так команда Rust называет эту недоделанную часть стандартной библиотеки. note: ведёт на задачу (issue) на GitHub, где её обсуждают.
Значит, rustc метод нашёл. Он точно знает, что ты имеешь в виду. Он просто не станет его компилировать, потому что intersperse всё ещё помечен как нестабильный (unstable): до завершения у него могут поменяться имя, аргументы или поведение, а может, его и вовсе уберут.
Другие формы заголовка значат то же самое, только для возможностей языка, а не библиотеки: the `!` type is experimental, `try` expression is experimental или associated type defaults are unstable.
Это как новый товар на полке магазина с наклейкой «только для сотрудников, ещё тестируем». Ты его видишь, можешь прочитать этикетку, но касса пока не даст его купить.
Почему Rust так делает
Заголовок раздела «Почему Rust так делает»Rust даёт сильное обещание: код, который компилируется на стабильном Rust сегодня, будет компилироваться и на каждой будущей стабильной версии Rust 1.x. Чтобы сдержать это обещание, новые возможности сначала появляются в канале nightly, где их можно попробовать и где их устройство ещё может измениться. Стабильной возможность становится, только когда готова, — обычно после месяцев или лет испытаний.
Стабильный Rust вообще отказывается компилировать нестабильные возможности, чтобы ты не строил на том, что может поменяться у тебя под ногами. Если очень хочется попробовать, в nightly возможность можно включить по имени через #![feature(iter_intersperse)]. На stable даже эта строка — ошибка (E0554).
Документация стандартной библиотеки показывает оба вида рядом. У стабильных элементов справа стоит номер версии, например 1.82.0, — версия Rust, в которой они стали стабильными. У нестабильных есть плашка «🔬 This is a nightly-only experimental API.» («это экспериментальный API только для nightly»). Эта плашка — самый быстрый способ заметить E0658 ещё до того, как ты напишешь код. Как каналы Rust и rustup связаны между собой, рассказано в уроке Инструменты Rust.
Как исправить
Заголовок раздела «Как исправить»Исправление 1: Используй стабильную альтернативу
Заголовок раздела «Исправление 1: Используй стабильную альтернативу»Это нужно почти всегда. Нестабильные методы обычно — сокращения для того, что стабильный Rust уже умеет. Чтобы склеить строки через разделитель, join у среза или Vec делает то же, что делал бы intersperse(...).collect():
fn main() { let tags = ["rust", "web", "cli"]; let joined = tags.join(", "); println!("{}", joined);
// Строки, созданные итератором: сначала собери их в Vec, потом соедини. let upper: Vec<String> = tags.iter().map(|t| t.to_uppercase()).collect(); println!("{}", upper.join(" | "));}Вывод:
rust, web, cliRUST | WEB | CLIЕсли хочется оставить всё одной цепочкой итераторов, в популярном крейте itertools есть стабильные join и intersperse для итераторов. Подробнее — в уроках Строки и Итераторы.
Исправление 2: Проверь в документации плашку «nightly-only»
Заголовок раздела «Исправление 2: Проверь в документации плашку «nightly-only»»Выбирай этот вариант, когда ты скопировал метод из документации, ответа ИИ или статьи. Открой метод в документации std: если там есть плашка 🔬, поищи чуть дальше стабильный способ. Частый пример — .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 informationПрограмма с ошибкой (комментарий значит «только для nightly»):
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 уже умеет это обычным collect(). Когда элементы — это Result, а собираешь ты в Result<Vec<_>, _>, получаешь Ok со всеми значениями или первую 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"]));}Вывод:
Ok([3, 14, 15])Err(ParseIntError { kind: InvalidDigit })Другие нестабильные методы, которые могут попасться, и их стабильные замены: .array_chunks() у итератора (iter_array_chunks; вместо него используй .as_chunks() или .chunks() у среза) и .map_windows() (используй .windows() у среза). Подробнее — в уроках Result и Срезы.
Исправление 3: Обнови Rust, если возможность стабилизировали недавно
Заголовок раздела «Исправление 3: Обнови Rust, если возможность стабилизировали недавно»Выбирай этот вариант, когда в документации вместо плашки 🔬 стоит номер версии или тот же код компилируется у друга или в Playground. Значит, возможность стабильна, просто она новее твоего компилятора. Например, as_chunks у срезов стал стабильным в Rust 1.88. На более старом Rust ты получил бы для него E0658, а на текущем он просто работает:
fn main() { let readings = [21, 22, 19, 20, 23]; let (pairs, rest) = readings.as_chunks::<2>(); for [a, b] in pairs { println!("{} и {}", a, b); } println!("осталось: {:?}", rest);}Вывод:
21 и 2219 и 20осталось: [23]Проверь свою версию и обнови Rust:
rustc --versionrustup updateЕсли после этого rustc --version всё ещё показывает старую версию, поищи в проекте файл rust-toolchain.toml. Он закрепляет за проектом одну версию Rust, а rustup show покажет, какая сейчас активна. Подробнее — в уроке Инструменты Rust.
Исправление 4: Включай nightly через #![feature], только если правда этого хочешь
Заголовок раздела «Исправление 4: Включай nightly через #![feature], только если правда этого хочешь»Выбирай этот вариант в последнюю очередь — только когда стабильной альтернативы нет и тебя устраивает, что код может сломаться на будущем nightly. Нужны две вещи: строка #![feature(...)] в начале main.rs (или lib.rs) с именем возможности из ошибки и компилятор nightly. На stable отклоняется уже сама строка #![feature]:
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 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^rustc пишет, что #![feature] нельзя использовать в стабильном канале. Программа, которая собирается только на nightly (комментарий значит «разрешено только в nightly Rust»):
#![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);}Установи nightly рядом со стабильным Rust и используй его только для этого проекта или этой команды:
rustup toolchain install nightlycargo +nightly runБудь честен с собой. Для учёбы, тестов и маленьких утилит nightly подходит. Для библиотеки, от которой зависят другие люди, или для всего, что тебе придётся поддерживать, оставайся на stable: большинство крейтов, которыми ты пользуешься, делают так же.
Где это обычно встречается
Заголовок раздела «Где это обычно встречается»Vec<i32, i32>, когда ты имел в виду список пар. Второй параметр Vec — аллокатор памяти, а он нестабилен, поэтому первая ошибка будет про allocator_api (за ней последуют ещё несколько):
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());}Комментарий значит «имелся в виду список пар (x, y)». Исправление: сделай, как говорит help, — Vec<(i32, i32)>. Подробнее — в уроках Векторы и Кортежи. Та же ошибка с Option или Result — это E0107.
Тип ! в твоих сигнатурах. ! значит «этого никогда не случится». Он работает как тип возврата функции, которая никогда не возвращается, но в любом другом месте пока нестабилен:
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());}Комментарий значит «здесь тип ! доступен только в nightly». Исправление: используй std::convert::Infallible — стабильный тип «эта ошибка невозможна» — или просто возвращай u16, если ничего не может пойти не так.
Блоки try. Блок try { ... } позволяет использовать ? без отдельной функции, но он только для nightly (`try` expression is experimental). Исправление: перенеси код в небольшую функцию, которая возвращает Result, и используй ? там, как в исправлении 2. Подробнее — в уроке Result.
Похоже, но не E0658: код, написанный для редакции 2024, например if let Some(a) = age && a >= 18, на более старой редакции даёт let chains are only allowed in Rust 2024 or later. Исправление: укажи edition = "2024" в Cargo.toml или вложи один if в другой.
Связанные ошибки
Заголовок раздела «Связанные ошибки»- E0554:
#![feature]may not be used on the stable release channel — ошибка-следствие, если попробовать исправление 4 на stable. - E0599: метод не найден; её ты получишь, если метода нет вообще (или он из крейта, который ты не добавил).
- E0107: неверное число обобщённых аргументов, например
Option<i32, i32>(родственник случая сVec<i32, i32>). - E0277: ограничение трейта не выполнено; одна из ошибок, которые идут после
Vec<i32, i32>. - E0463: крейт не найден — если перейдёшь на
itertoolsи забудешь добавить его вCargo.toml. - Все ошибки компилятора: полный список страниц об ошибках.
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. На странице метода в документации std есть плашка «This is a nightly-only experimental API». Что будет, если вызвать его на стабильном Rust?
2. .try_collect() даёт E0658. Каким обычным стабильным способом превратить итератор из Result в Result<Vec<_>, _>?
3. Код компилируется в Playground, а у тебя даёт E0658 для метода, у которого в документации стоит 1.88.0. Что попробовать сначала?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- E0658 — Rust error codes index (на английском): официальное объяснение и как строка
#![feature]включает возможность в nightly. - Как создаётся Rust и «Nightly Rust» — книга «Язык программирования Rust» (перевод на русский): stable, beta и nightly, «поезд релизов» и как нестабильные возможности становятся стабильными.
- Channels — The rustup book (на английском): установка nightly,
cargo +nightlyи выбор тулчейна для проекта. - The Unstable Book (на английском): все имена нестабильных возможностей, которые можно увидеть в E0658, с коротким описанием каждой.
slice::join— документация стандартной библиотеки (на английском): стабильный способ соединить строки через разделитель, заменаintersperse.