Rustのコンパイルエラー解説
Rust のコンパイラから赤いエラーが出て、何を言われているのかよくわからない……そんなときは、このページから始めましょう。こうしたエラーは、Rust を書く人なら誰でも、ときには1日に何度も目にするものです。うれしいことに、何度も出会うエラーはほんのいくつかしかありません。一度わかってしまえば、もう怖くありません。
下の各ページでは、エラーコードを1つずつ取り上げて、実際のメッセージを見せ、その意味をやさしい言葉で説明し、ブラウザで実行できる直し方を紹介します。
よく出るエラー
Section titled “よく出るエラー”| エラー | コンパイラのメッセージ | ひとことで言うと |
|---|---|---|
| E0382 | borrow of moved value | 値を渡してしまったあとで、もう一度使おうとした |
| E0502 | cannot borrow as mutable because it is also borrowed as immutable | 誰かがまだ読んでいる最中に、その値を書き換えようとした |
| E0499 | cannot borrow as mutable more than once at a time | 2か所が同時に同じ値を書き換えようとした |
| E0308 | mismatched types | 期待されている型とは違う型を渡した |
| E0277 | the trait bound is not satisfied | その型には、頼んだこと(表示・比較・足し算など)ができない |
| E0106 | missing lifetime specifier | 返した参照がいつまで有効なのか、Rust にはわからない |
| E0425 | cannot find value in this scope | 名前のつづりが違うか、その名前が使えるブロックの外で使っている |
| E0599 | no method named … found | その型にはそのメソッドがないか、トレイトを use していない |
| E0384 | cannot assign twice to immutable variable | mut を付けていない変数を書き換えた |
| E0596 | cannot borrow as mutable, as it is not declared as mutable | mut でない変数や参照を通して、値を書き換えようとした |
| E0597 | borrowed value does not live long enough | 指している値がなくなったあとも、参照を使おうとしている |
| E0515 | cannot return reference to local variable | 関数の終わりで破棄される値への参照を返した |
| E0373 | closure may outlive the current function, but it borrows … | クロージャ(よくあるのはスレッド)が、先になくなるかもしれないローカル変数を借用している |
| E0369 | binary operation == cannot be applied to type … |
自分の型が ==、<、+ などに(まだ)対応していない |
| E0432 | unresolved import | use の行が、見つからないクレート・モジュール・アイテムを指している |
| E0433 | cannot find type … in this scope (older: failed to resolve) | HashMap::new() のようなパスに、インポートしていない(または存在しない)名前が使われている |
| E0424 | self value is a keyword only available in methods with a self parameter |
self を受け取らない関数の中で self を使った |
| E0061 | this function takes N arguments but M arguments were supplied | 引数が多すぎるか少なすぎる(Rust には省略可能な引数がない) |
| E0594 | cannot assign to p.hp, as p is not declared as mutable |
mut でのアクセスなしに、フィールドや & の先の値を書き換えた |
| E0004 | non-exhaustive patterns: X not covered |
match がありうる値をすべて扱っていない |
| E0507 | cannot move out of x which is behind a shared reference |
借りているだけのものの所有権を取ろうとした |
| E0603 | function x is private |
pub でない関数・構造体・モジュールを使った |
| E0716 | temporary value dropped while borrowed | 行の終わりで捨てられる値への参照を持ち続けた |
| E0463 | can’t find crate for x |
クレート(またはターゲット用の標準ライブラリ)がインストールされていない |
| E0368 | binary assignment operation += cannot be applied to type … |
自分の型が +=、-= などに対応していない |
| E0057 | this function takes N arguments but M were supplied (note: closure defined here) | クロージャを呼ぶときの引数が多すぎるか少なすぎる |
| E0282 | type annotations needed | Rust が自分で型を決められないので、型を書いてあげる必要がある |
| E0609 | no field x on type T |
フィールド名のつづりが違うか、値が(Option などに)包まれている |
| E0593 | closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments | タプル(または別の数の引数)が期待されているのに、クロージャが別々の引数を受け取っている |
| E0631 | type mismatch in closure arguments | クロージャの引数の型が、渡される値と合わない(i32 と &i32 の違いが多い) |
| E0005 | refutable pattern in local binding | let Some(x) = … は失敗することがあるので、ふつうの let では受け付けてもらえない |
| E0615 | attempted to take value of method len on type String |
s.len() ではなく s.len と書いた |
| E0610 | {integer} is a primitive type and therefore doesn’t have fields |
数値・bool・char に .field を付けた |
| E0560 | struct User has no field named nmae |
構造体を作るときに、その構造体にないフィールド名を書いた |
| E0616 | field balance of struct Account is private |
pub でないフィールドを、モジュールの外から読んだ |
| E0451 | field x of struct Y is private |
非公開のフィールドがある構造体を、構造体リテラルで作ろうとした |
| E0624 | method x is private |
pub でないメソッドや関連関数を呼んだ |
| E0283 | type annotations needed (cannot infer type … multiple impls satisfy this bound) | 当てはまる型がいくつもある(.collect()、.sum() など)ので、1つ選ぶ必要がある |
| E0284 | type annotations needed: cannot satisfy <_ as FromStr>::Err == _ |
"42".parse() が、どの型にパースすればいいのかわからない |
| E0790 | cannot call associated function on trait without specifying the corresponding impl type |
どの型なのかを書かずに Default::default() や Trait::new() を呼んだ |
| E0559 | variant Shape::Circle has no field named r |
列挙型のバリアントを作るときに、そのバリアントにないフィールド名を書いた |
| E0063 | missing field email in initializer of User |
構造体を作るときに、フィールドを1つ以上書き忘れた |
| E0689 | can’t call method pow on ambiguous numeric type {integer} |
2.pow(10) や 2.0.sqrt() には、i32 や f64 のような具体的な数値の型が必要 |
| E0034 | multiple applicable items in scope | 2つのトレイトが同じ名前のメソッドを型に与えていて、Rust がどちらか選べない |
| E0412 | cannot find type X in this scope (Rust 1.93+ prints E0425) |
型の名前のつづりが違うか、インポートや宣言をしていない |
| E0428 | the name area is defined multiple times |
2つのアイテムが同じ名前を使っている(Rust には関数のオーバーロードがない) |
| E0026 | variant Shape::Circle does not have a field named r |
パターンに、構造体やバリアントにないフィールドの名前を書いている |
| E0027 | pattern does not mention fields id, paid |
構造体のパターンにフィールドが足りない。追加するか、最後に .. を書く |
| E0533 | expected unit struct, unit variant or constant, found struct variant Shape::Circle |
ただの名前が来るべき場所で、構造体バリアント(や関数)を使っている。{ .. } を付ける |
| E0592 | duplicate definitions with name reset |
2つの impl ブロックで、同じ名前のメソッドを定義している |
| E0255 | the name Error is defined multiple times |
use でインポートした名前が、自分の型や関数と同じ |
| E0252 | the name Result is defined multiple times |
2つの use の行が同じ名前を持ち込んでいる。片方を as で名前を変える |
| E0411 | cannot find type Self in this scope |
impl やトレイトの外で Self を使った |
| E0405 | cannot find trait Display in this scope |
トレイトの名前のつづりが違うか、インポートしていない(例:use std::fmt::Display;) |
| E0532 | expected unit struct, unit variant or constant, found tuple variant Shape::Circle |
パターンでタプルバリアント(や構造体)の ( ) を書き忘れたか、いらない ( ) を付けている |
| E0164 | expected tuple struct or tuple variant, found struct variant Shape::Circle |
パターンで、構造体バリアントや関連アイテムに ( ) を付けている。{ } かマッチガードを使う |
| E0404 | expected trait, found derive macro Debug |
impl X for や T: X の X が、構造体や型エイリアス、インポートしていない derive マクロになっている |
| E0401 | can’t use generic parameters from outer item | 内側の fn が外側の関数の T や Self を使っている。自分のジェネリクスを付けるか、クロージャを使う |
| E0107 | enum takes 2 generic arguments but 1 generic argument was supplied | Result<u32> や HashMap<String> など、< > の中の型が足りないか多すぎる |
| E0530 | match bindings cannot shadow tuple variants | (use Shape::* のあとの)Circle => のような、( ) のないバリアント名は新しい変数にできない |
| E0434 | can’t capture dynamic environment in a fn item | 内側の fn からは外側のローカル変数が見えない。クロージャを使うか、引数で渡す |
| E0601 | main function not found in crate main |
バイナリに fn main() がない(書き忘れ、つづりの間違い、mod の中にある、本当はライブラリ) |
| E0658 | use of unstable library feature iter_intersperse |
stable の Rust で nightly 専用の API を使った。stable の代わりの方法を使うか、Rust を更新する |
| E0614 | type u32 cannot be dereferenced |
x が参照ではなくただの値なのに、*x と書いた |
| E0435 | attempt to use a non-constant value in a constant | const、配列の長さ、static に let の変数を使った。const にするか、Vec を使う |
| E0554 | #![feature] may not be used on the stable release channel |
nightly 専用のコードをコピーした。属性を消して stable の API を使うか、わかったうえで nightly を使う |
表の真ん中の列は、ターミナルに表示されるとおり英語のままにしています。rustc のエラーメッセージは、どの国でも英語で表示されるからです。
Rust のエラーの読み方
Section titled “Rust のエラーの読み方”Rust のエラーメッセージはとても親切なことで有名ですが、情報がぎっしり詰まっています。実際の例を見てみましょう。
fn main() { let name = String::from("Ferris"); let greeting = name; println!("{name}");}error[E0382]: borrow of moved value: `name` --> src/main.rs:4:16 |2 | let name = String::from("Ferris"); | ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait3 | let greeting = name; | ---- value moved here4 | println!("{name}"); | ^^^^ value borrowed here after move |help: consider cloning the value if the performance cost is acceptable |3 | let greeting = name.clone(); | ++++++++次の順番で読んでいきます。
- 最初の行は要約です。エラーコード(
E0382)と、1行の説明が書かれています。 - 矢印の行(
--> src/main.rs:4:16)は、問題が起きたファイル・行・列を教えてくれます。 ^^^^の印は、エラーが起きたちょうどその場所を指しています。----の印は、そこに至るまでの経緯です。この例では「値は2行目で作られ、3行目でムーブされ、4行目で使われた」と言っています。help:は、コンパイラがおすすめする直し方です。追加すべきコードがそのまま書かれていることもよくあります(++++の印が新しく足す文字です)。いつも最善の直し方とは限りませんが、出発点としてはとても役に立ちます。
読み始めるのは最初のエラーからです。1つの間違いが、あとに続くエラーを次々と引き起こすことがあります。最初の1つを直すだけで、残りが消えてしまうこともよくあります。
役に立つ3つの習慣
Section titled “役に立つ3つの習慣”-
コンパイラにもっと詳しく聞く。 どのエラーコードにも、長めの説明が組み込まれています。ターミナルで次のように実行してみましょう。
Terminal window rustc --explain E0382短い説明と、エラーになる例、直した例が表示されます(説明は英語です)。
-
こまめにチェックする。
cargo checkはプログラム全体をビルドせずにエラーを見つけるので、cargo buildよりずっと速く終わります。数行書くたびに実行すれば、エラーに出会うのは一度に1つずつで済み、20個まとめて、ということにはなりません。詳しくはCargoとクレートを見てください。 -
書いている最中にエディタでエラーを表示する。 rust-analyzer 拡張機能を使うと、同じ help のテキスト付きで、エラーがコードの中に直接表示されます。詳しくはRustのツールと環境構築を見てください。
Rust にエラーが多い理由
Section titled “Rust にエラーが多い理由”ここに並んでいるエラーのほとんどは、ほかの言語なら実行時になって(あるいは永遠に)気づかないことを、Rust がプログラムを実行する前にチェックしているから存在します。解放済みのメモリを使う、2つのスレッドが同じデータを書き換える、null のチェックを忘れる、といったことです。エラーを1つ直すたびに、ユーザーのもとに届くはずだったバグが1つ消えています。
だから「Rust ではコンパイル時に戦って、そのあとはプログラムがそのまま動く」とよく言われます。よく出るエラーの背景にあるルールは、所有権、借用、ライフタイムで解説しています。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. Rust のエラーにいくつか問題が表示されました。最初に直すべきなのはどれですか?
2. rustc --explain E0382 は何をしますか?
3. エラーメッセージの中で、^^^^ の印は何を示していますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- Rust Compiler Error Index(英語):すべてのエラーコードの公式一覧です。それぞれにエラーになる例と直した例が載っています。
- 所有権を理解する — The Rust Programming Language 日本語版:借用やムーブにまつわる、よく出るエラーの背景にあるルールです。
- エラー処理 — The Rust Programming Language 日本語版:コンパイルエラーではなく、自分のプログラムの中でエラーをどう扱うか(
Resultとpanic!)を解説しています。 - What is rustc? — The rustc Book(英語):コンパイラのしくみと、フラグや lint レベルの説明です。