コンテンツにスキップ

Rustのエラー E0658: use of unstable library feature(nightly専用の不安定な機能)

E0658 は、Rust に存在はするけれど、まだ完成していないものを使ったので、stable の Rust では使わせてもらえない、という意味のエラーです。たいていは、標準ライブラリのドキュメントやブログ記事で見つけた .intersperse() や .try_collect() のようなメソッドか、try { ... } のような構文です。コードが間違っているわけではありませんし、パソコンの何かが壊れているわけでもありません。nightly のコンパイラでしか動かない機能に手を伸ばしただけです。ほとんどの場合、同じことをする stable の方法が1行で書けます。このシリーズのほかのエラーは、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

「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 専用のメソッド」という意味です(エラーになる例なので、コードはそのままにしています)。

^^^^^^^^^^^ は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 は強い約束をしています。今日の 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, cli
RUST | 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 と 22
19 と 20
余り: [23]
▶ 実際に試してみよう

バージョンを確かめて、更新しましょう。

Terminal window
rustc --version
rustup 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 をインストールし、このプロジェクトやこのコマンドだけで使いましょう。

Terminal window
rustup toolchain install nightly
cargo +nightly run

ここは自分に正直になりましょう。学習やテスト、小さなツールなら nightly でもかまいません。でも、ほかの人が使うライブラリや、ずっとメンテナンスしなければならないものなら、stable のままにしておきましょう。使っているクレートのほとんども stable です。

ペアのリストのつもりで 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 を入れ子にします。

  • 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 に追加し忘れたとき。
  • コンパイルエラーの一覧:エラー解説ページの全リストです。

理解度チェック

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