Rustのエラー E0658: use of unstable library feature(nightly専用の不安定な機能)
E0658 は、Rust に存在はするけれど、まだ完成していないものを使ったので、stable の Rust では使わせてもらえない、という意味のエラーです。たいていは、標準ライブラリのドキュメントやブログ記事で見つけた .intersperse() や .try_collect() のようなメソッドか、try { ... } のような構文です。コードが間違っているわけではありませんし、パソコンの何かが壊れているわけでもありません。nightly のコンパイラでしか動かない機能に手を伸ばしただけです。ほとんどの場合、同じことをする stable の方法が1行で書けます。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”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「use of unstable library feature iter_intersperse」は「不安定なライブラリ機能 iter_intersperse を使っている」、note は「詳しくは issue #79524 を見てください」という意味です。
このエラーが出るのは、次のプログラムです。
fn main() { let tags = ["rust", "web", "cli"]; let joined: String = tags.iter().copied().intersperse(", ").collect(); // ❌ nightly-only method println!("{}", joined);}コメントは「nightly 専用のメソッド」という意味です(エラーになる例なので、コードはそのままにしています)。
エラーの意味
Section titled “エラーの意味”^^^^^^^^^^^ は3行目の intersperse を指しています。見出しには、バッククォートで囲まれた機能名(feature name)iter_intersperse が書かれています。これは、標準ライブラリのこの未完成の部分を、Rust チームが呼ぶときの名前です。note: には、その機能について話し合っている GitHub の issue へのリンクがあります。
つまり rustc はメソッドを見つけています。何をしたいのかも正確にわかっています。ただ、intersperse がまだ不安定(unstable)とされているので、コンパイルしないのです。完成する前に、名前や引数、動きが変わるかもしれませんし、なくなってしまうかもしれません。
見出しがほかの形のときも、意味は同じです。ライブラリではなく言語の機能の場合で、the `!` type is experimental(! 型は実験的)、`try` expression is experimental(try 式は実験的)、associated type defaults are unstable(関連型のデフォルトは不安定)などがあります。
お店の棚に新商品が並んでいるのに、「スタッフ専用・テスト中」のシールが貼ってあるようなものです。見ることも、ラベルを読むこともできますが、レジではまだ売ってもらえません。
Rust がこうする理由
Section titled “Rust がこうする理由”Rust は強い約束をしています。今日の stable の Rust でコンパイルできるコードは、これからの stable の Rust 1.x でもずっとコンパイルできる、という約束です。それを守るために、新しい機能はまず nightly チャネルに入ります。そこでみんなが試して、設計を変えることもできます。機能が完成してはじめて stable になります。ふつうは、何か月も、あるいは何年もテストされたあとです。
stable の Rust は、不安定な機能のコンパイルを一切拒みます。だから、足元で変わるかもしれないものの上にコードを築いてしまうことはありません。どうしても試したいなら、nightly では #![feature(iter_intersperse)] のように名前を指定して、その機能を有効にできます。stable では、その行さえエラー(E0554)になります。
標準ライブラリのドキュメントには、両方の種類が並んで載っています。stable のアイテムには、右側に 1.82.0 のようなバージョン番号があります。それが stable になった Rust のバージョンです。不安定なアイテムには、「🔬 This is a nightly-only experimental API.」(これは nightly 専用の実験的な API です)という囲みがあります。コードを書く前に E0658 を見つけるには、この囲みを見るのがいちばんの近道です。Rust のチャネルと rustup の関係については、Rustのツールと環境構築を見てください。
直し方1:stable の代わりの方法を使う
Section titled “直し方1:stable の代わりの方法を使う”ほとんどの場合はこれを選びます。不安定なメソッドの多くは、stable の Rust でもうできることの近道です。区切り文字を挟んで文字列をつなげるなら、スライスや Vec の join が、intersperse(...).collect() と同じことをしてくれます。
fn main() { let tags = ["rust", "web", "cli"]; let joined = tags.join(", "); println!("{}", joined);
// イテレータで作った文字列は、いったん Vec に集めてから join する。 let upper: Vec<String> = tags.iter().map(|t| t.to_uppercase()).collect(); println!("{}", upper.join(" | "));}実行結果:
rust, web, cliRUST | WEB | CLIすべてを1つのイテレータのチェーンのままにしておきたいなら、人気の itertools クレートに、イテレータ用の stable な join と intersperse があります。詳しくは文字列とイテレータを見てください。
直し方2:ドキュメントで「nightly-only」の印を確かめる
Section titled “直し方2:ドキュメントで「nightly-only」の印を確かめる”ドキュメントや AI の回答、ブログ記事からメソッドをコピーしたときは、これを選びます。std のドキュメントでそのメソッドを開き、🔬 の囲みがあったら、もう少し先まで読んで stable の方法を探しましょう。よくあるのが .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このエラーが出るプログラムです。
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);}stable の 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 })ほかにも出会うことのある不安定なメソッドと、その stable な方法です。イテレータの .array_chunks()(iter_array_chunks。代わりにスライスの .as_chunks() か .chunks() を使う)と、.map_windows()(スライスの .windows() を使う)です。詳しくはResultとスライスを見てください。
直し方3:最近 stable になった機能なら、Rust を更新する
Section titled “直し方3:最近 stable になった機能なら、Rust を更新する”ドキュメントに 🔬 の囲みではなくバージョン番号が載っているときや、同じコードが友だちのパソコンや Playground ではコンパイルできるときは、これを選びます。その場合、機能は stable になっていて、あなたのコンパイラより新しいだけです。たとえば、スライスの as_chunks は Rust 1.88 で stable になりました。古い Rust では E0658 になりますが、今の Rust ならそのまま動きます。
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]バージョンを確かめて、更新しましょう。
rustc --versionrustup update更新したあとも rustc --version が古いバージョンのままなら、プロジェクトに rust-toolchain.toml というファイルがないか探してみてください。これはプロジェクトを1つの Rust のバージョンに固定するファイルです。どのバージョンが有効になっているかは、rustup show で確かめられます。詳しくはRustのツールと環境構築を見てください。
直し方4:本当にそのつもりなら、#![feature] で nightly を使う
Section titled “直し方4:本当にそのつもりなら、#![feature] で nightly を使う”これは最後の手段です。stable の代わりの方法がなく、将来の nightly でコードが壊れてもかまわないときだけ選びましょう。必要なものは2つです。main.rs(または lib.rs)のいちばん上に、エラーに出ていた機能名を書いた #![feature(...)] の行と、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 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^「#![feature] may not be used on the stable release channel」は「#![feature] は stable のリリースチャネルでは使えない」という意味です。
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);}stable の Rust と並べて nightly をインストールし、このプロジェクトやこのコマンドだけで使いましょう。
rustup toolchain install nightlycargo +nightly runここは自分に正直になりましょう。学習やテスト、小さなツールなら nightly でもかまいません。でも、ほかの人が使うライブラリや、ずっとメンテナンスしなければならないものなら、stable のままにしておきましょう。使っているクレートのほとんども stable です。
よく出会う場面
Section titled “よく出会う場面”ペアのリストのつもりで Vec<i32, i32> と書いた。 Vec の2つ目の型引数はメモリのアロケータで、これは不安定です。だから最初のエラーは 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());}help は「中の型をタプルで包んではどうか:(i32, i32)」、コメントは「(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 専用」という意味です。直し方:「このエラーは起こりえない」を表す stable の型、std::convert::Infallible を使うか、失敗することがないなら、ただ u16 を返します。
try ブロック。 try { ... } ブロックを使うと、関数を書かなくても ? が使えますが、これは nightly 専用です(`try` expression is experimental)。直し方:そのコードを Result を返す小さな関数に移し、直し方2のように、そこで ? を使います。詳しくはResultを見てください。
関連はありますが、E0658 ではないもの:if let Some(a) = age && a >= 18 のような 2024 エディション向けに書かれたコードは、古いエディションでは let chains are only allowed in Rust 2024 or later(let チェーンは Rust 2024 以降でだけ使える)になります。直し方:Cargo.toml で edition = "2024" にするか、2つの if を入れ子にします。
関連するエラー
Section titled “関連するエラー”- E0554:
#![feature]may not be used on the stable release channel。stable で直し方4を試したときに続けて出るエラーです。 - E0599:no method found。メソッドがまったく存在しない(または、まだ追加していないクレートのメソッドだ)とき、E0658 ではなくこちらが出ます。
- E0107:ジェネリック引数の数が違う。
Option<i32, i32>のようなときで、Vec<i32, i32>のケースの親戚です。 - E0277:トレイト境界を満たしていない。
Vec<i32, i32>のあとに続くエラーの1つです。 - E0463:can’t find crate。
itertoolsに切り替えたのに、Cargo.tomlに追加し忘れたとき。 - コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. std のドキュメントで、あるメソッドのページに「This is a nightly-only experimental API」という囲みがあります。stable の Rust で呼ぶとどうなりますか?
2. .try_collect() が E0658 になりました。Result のイテレータを Result<Vec<_>, _> にする、ふつうの stable な方法はどれですか?
3. Playground ではコンパイルできるコードが、手元では E0658 になります。そのメソッドのドキュメントには 1.88.0 とあります。まず何を試すべきですか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0658 — Rust error codes index(英語):このエラーの公式の説明です。nightly で
#![feature]の行を使って機能を有効にする方法も載っています。 - 付録G:Rustの作られ方と“Nightly Rust” — The Rust Programming Language 日本語版:stable、beta、nightly、リリーストレイン、そして不安定な機能が stable になるまでの流れです。
- Channels — The rustup book(英語):nightly のインストール、
cargo +nightly、プロジェクトごとのツールチェーンの設定です。 - The Unstable Book(英語):E0658 に出てくる不安定な機能の名前が全部載っていて、それぞれに短い説明があります。
slice::join— standard library docs(英語):区切り文字を挟んで文字列をつなげる stable の方法で、intersperseの代わりになります。