Skip to content
Tech AI Wire
Coding解説

Rustのnever型とは何か、解説

Rustのnever型は「!」と書き、値を決して生まないコードの型です。10年を経てRust 1.100で安定になり、型フォールバックも変わります。

著者 Tech AI Wire Team

5 分で読めます

左から右へ明るくなる5つの濃いグレーの正方形が並び、最後に赤い正方形が1つ置かれている。

数字で見る

RFC 1216 proposed making ! a real type
2015
crates crater compiled against the stabilization
9,024
of them flagged as regressions
3,277

Rustのnever型は、値を決して生まない式の型です。感嘆符1つ、!で書きます。常にパニックするか、無限に回るか、途中で戻る関数はこの型を持ちます。後続のコードに値を決して渡さないからです。不安定な機能として10年を過ごしたのち、never型はいま安定になりました。それを実現したプルリクエストは2026年8月24日にマージされ、1つの破壊的変更を伴っています。

これはコンパイラの豆知識にとどまらない話です。never型はあなたのコードの行き止まりで何が起きるかを決め、新しいフォールバック規則は汎用関数が推論する型を変えることがあります。The Rust Reference!を、値を持たない型、決して完了しない計算を表す型と定義しています。

仕組み

型とは、取りうる値の集合です。bool型には値が2つあります。never型には1つもありません。すべての始まりとなった2015年の提案、RFC 1216は、そのような型を空の型、「その型に属するものが何も存在しない型」と呼んでいます。プログラムの実行中に!型のものが存在することはないので、その型の値には機械レベルの表現がまったくありません。

この空であることが、!に唯一の特別な力を与えます。Rust標準ライブラリのドキュメントによれば、!型の式は他のどんな型にも型強制できます。コンパイラがそれを安全に約束できるのは、その型強制が決して実行されないからです。panic!()の後のコードがStringを期待していても、パニック式はそこに収まります。そこでStringが必要になることは決してないからです。returnbreakcontinuepanic!()のすべてが、別の型を期待する位置に置けるのはこのためです。

標準ライブラリは、!がClone、Copy、Debug、Display、Eq、Hash、Ord、PartialEq、PartialOrd、Errorを実装すると記しています。同じドキュメントは、決して実装すべきでないトレイトを1つ挙げています。Defaultです。Defaultは値を生まなければなりませんが、!にはそれができません。

この安定化より前、安定版のRustで!を書けるのは1か所だけ、関数の戻り値の型としてでした。リファレンスがそう記しています。他の場所で空の型が必要な開発者は自作していました。たいていはenum Never {}で、RFC 1216が説明しているパターンです。標準ライブラリ自身の版がstd::convert::Infallibleです。バリアントを持たないenumで、Rust 1.34.0からライブラリに入っています。そのドキュメントは、決して起こりえないエラーのためのエラー型と説明しています。Result<T, Infallible>は、結果が常にOkだと読み手に伝えます。

何が、いつ変わったか

PRによれば、プルリクエスト155499では3つのことが同時に入りました。第一に、!が本物の型として安定になりました。RFC 1216が2015年に求めたものです。第二に、Infallible!の型エイリアスになり、2つの名前はいま同じ型を意味します。第三に、これが破壊的な部分ですが、型フォールバックはどのRustエディションでも!へ解決されるようになりました。

フォールバックは、ある1つのコーナーケースのための規則です。コンパイラは時に、式が発散し、周囲の何もその型を定めない箇所に行き着きます。従来はその箇所でユニット型()、つまり空タプルを選んでいました。2024エディション以降について、標準ライブラリのドキュメントはすでにフォールバックを!だと説明しています。安定化のPRはそれを、古いエディションを含むすべての場所での規則にします。

Rustプロジェクトはマージ前にこの変更を計測しました。PRは9,024個のクレートに対するcraterの実行を報告しています。craterは、公開されたクレートの大きな標本を提案中のコンパイラでコンパイルし、何が壊れるかを報告します。3,277件のリグレッションを検出し、修正されたものは0件でした。PRはRust 1.100.0のマイルストーンに入っています。マージ時にTech AI Wireの安定化に関する報道が記した通りです。

リグレッション報告の1つが教訓になります。あるコントリビューターが、クレートのAPIの破壊的変更を検査するツールcargo-semver-checksが、Infallibleの変更を破壊的だと報告したことを指摘しました。PRの議論はそれを偽陽性と呼んでいます。コントリビューターのJonathanBrouwerはこう述べました。「型はまだそこにある。pub enumからpub typeに変わっただけだ」。

節目時期何が起きたか
RFC 12162015年7月19日!を本物の型へ格上げすると提案
追跡Issue 351212016年7月29日RFCを追跡するため開設。PR 35162が最初の実装
PR 65355Rust 1.41.0最初の安定化。リグレッションによりPR 67224で差し戻し
Rust 2024エディション2024エディションまず新エディション内でフォールバックを!へ変更
PR 1554992026年8月24日!が安定、フォールバックが全体に適用、Infallibleがエイリアス化

なぜ10年かかったのか

追跡Issueが遅れの物語を語っています。Issue 35121は2016年7月29日に開かれました。最初の安定化はRust 1.41.0で出荷され、その後取り出されました。実在するクレートが壊れたからです。Issueはそのきっかけを記録しています。InfallibleからのError変換がコンパイルできなくなり、Issue 66757として報告されました。最終的なPRの作者は自身のブログで、失敗した試みは全部で5回あったと書いています。この最後の取り組みには2年以上かかりました。

抜け道は段階的に進めることでした。追跡Issueは3段階の計画を示しています。2024エディション内だけでフォールバックを!へ変える。そのエディションを安定化する。そしてエコシステムが新しい規則を吸収してから、破壊的変更を全体に適用し、Infallible!と等しくする。2026年8月のPRがその最終段階です。今年のRustのもう1つの大きなコンパイラ変更である次世代トレイトソルバーも、同じ慎重なやり方でまずnightlyを通っており、安定化は後の予定です。

開発者にとっての意味

Rust 1.100.0がstableに届く前に、汎用コードをnightlyで確認してください。フォールバックの変更が問題になるのは、型引数が、パニックするか早く戻る式によってのみ定まる場所です。そうした箇所で、コンパイラは以前あなたのために()を選んでいましたが、いまは!を選びます。ほとんどのコードは気づきません。古い選択に依存していたコードは、コンパイルに失敗するか、別のトレイト実装を選ぶことがあります。craterの3,277件のヒットは、それが仮定の話ではないことを示しています。

Infallibleをgrepしてください。あなたのクレートがInfallible!の両方に対して同じトレイトを実装しているなら、その2つの実装はいま衝突します。1つの型を指しているからです。Infallibleのドキュメントは、fn() -> !fn() -> Infallibleのような関数ポインタ型が異なるトレイト実装を持ちえたことも記しています。それらもいま一致します。公開APIでInfallibleを公開しているライブラリは、semverツールが何と言おうと、利用者を壊しません。型は両方の名前の下にまだそこにあります。

これからは!を意図して使ってください。成功しかしない関数はResult<T, !>を返せます。RFC 1216が動機となるユースケースとして挙げているもので、呼び出し側はOkの腕だけでmatchできます。決して戻らないハンドラは、Fn() -> Tを期待する汎用コードに、ラッパー型なしで渡せます。これもRFCのユースケースの1つです。サポートする最低Rustバージョンが許すようになったら、自作のenum Never {}は捨ててください。

1文字の型にとって、10年は長い時間です。差し戻された最初の試み、エディション先行の展開、そしてcraterの数字が、その大半を説明しています。それらはまた、この変更がstableに届く前に、今日nightlyで備えられる理由でもあります。

出典

  1. Never type - The Rust Reference - The Rust Reference
  2. Primitive type ! - Rust standard library documentation - Rust standard library docs
  3. RFC 1216: Promote ! to a type - Rust RFCs
  4. stabilize never type (PR #155499) - GitHub - rust-lang/rust
  5. Tracking issue for RFC 1216 (promoting ! to a type) - GitHub - rust-lang/rust
  6. Enum std::convert::Infallible - Rust standard library documentation - Rust standard library docs

関連記事

A terminal window showing a C++ project being linked with mold, with the elapsed link time visible in the output.
Dev Stack

moldのRust書き換え、Linuxの標準リンカを目指す

moldはLLVMのlldより中央値で4.9倍速くリンクします。作者はこれをRust(ラスト)で書き直し、ディストリビューションに/usr/bin/ldとして採用させることを狙っています。