Rustのエラーを直して覚える
実際に出力されるメッセージを読みながら、空欄を埋めて直します。全170問。間違えた問題は翌日・3日後・7日後に自動で再出題されます。
エラー別に調べる
初級
- E0384: cannot assign twice to immutable variable の原因と直し方Rustの変数はデフォルトで不変(immutable)です。letで宣言した変数に後から再代入しようとすると、コンパイル時にE0384エラーになります。
- E0308: mismatched types(型の不一致)の原因と直し方変数の型注釈と実際に代入する値の型が食い違うと、コンパイル時にE0308エラーになります。Rustは暗黙の型変換を行わないため、型はすべて一致している必要があります。
- 末尾にセミコロンを付けると戻り値が () になり E0308 になるRustの関数は最後の行が式(セミコロン無し)であれば、その値をそのまま戻り値にします。セミコロンを付けるとその行は文(statement)になり、戻り値が空のタプル()に変わってしまいます。
- index out of bounds パニックの原因と直し方存在しない添字でVecや配列にアクセスすると、コンパイルは通りますが実行時にパニックしてプログラムが異常終了します。
- called `Option::unwrap()` on a `None` value パニックの原因と直し方Option<T>型の値がNoneのときにunwrap()を呼び出すと、パニックが発生してプログラムが異常終了します。findやgetなど、見つからない可能性のある操作の戻り値はOptionになります。
- called `Result::unwrap()` on an `Err` value パニックの原因と直し方文字列を数値に変換するparse()などはResult<T, E>型を返します。変換に失敗してErrになった状態でunwrap()を呼ぶと、パニックが発生します。
- E0382: borrow of moved value(ムーブ後の値の使用)の原因と直し方StringやVecのようにCopyトレイトを実装しない値を別の変数に代入すると、所有権が移動(ムーブ)します。ムーブ後に元の変数を使おうとすると、コンパイル時にE0382エラーになります。
- E0369: cannot add `&String` to `&str` の原因と直し方文字列リテラル(&str)を左側にして+で連結しようとすると、+演算子がStringの左辺にしか実装されていないためE0369エラーになります。
- E0425: cannot find value in this scope の原因と直し方宣言していない変数名を参照すると、コンパイル時にE0425エラーになります。変数名のタイプミスが典型的な原因です。
- 整数同士の割り算 / が小数にならず切り捨てられるi32同士の/演算子は、商の整数部分だけを返します。小数点以下は切り捨てられ、割り切れなくても整数のままです。
- attempt to divide by zero パニックの原因と直し方整数を0で割ると、実行時にパニックが発生しプログラムが異常終了します。0になりうる値は、割り算の前に事前チェックが必要です。
- E0596: cannot borrow as mutable の原因と直し方mutを付けずに宣言した変数を、&mutで可変参照として渡そうとするとE0596エラーになります。値を変更する関数に渡す変数は、宣言時からmutにしておく必要があります。
- E0061: this function takes N arguments but M were supplied の原因と直し方関数が定義している数と異なる数の引数を渡すと、コンパイル時にE0061エラーになります。引数を1つ多く渡した、あるいは渡し忘れたことが典型的な原因です。
- if の条件式に整数を渡すと E0308(expected bool)になるC言語やJavaScriptと違い、Rustのif文の条件式には真偽値(bool)しか書けません。0や1のような整数をそのまま条件に置くとE0308エラーになります。
中級
- E0502: cannot borrow as mutable because it is also borrowed as immutable不変参照が生きている(後で使われる)間に、同じ変数を可変で借用しようとするとE0502エラーになります。Rustの借用規則は「不変参照は何個でも、可変参照は同時に1つだけ」を強制します。
- for ループで Vec を直接回すと要素がムーブされるfor x in vec のように所有権を持つVecを直接forに渡すと、内部でinto_iter()が呼ばれ各要素の所有権がムーブされます。ループの後で元のVecを使おうとするとE0382エラーになります。
- attempt to subtract with overflow パニックの原因と直し方符号なし整数(usizeなど)で0から1を引くような演算を行うと、負の値を表現できないため実行時にパニックします。Vecの長さから1を引く処理で、空のVecを渡すと典型的に発生します。
- HashMapを存在しないキーで [] 添字アクセスすると no entry found for key パニックになるHashMapに[]で添字アクセスした際、そのキーが存在しないとパニックします。存在するかどうか分からないキーを扱う場合は、getメソッドを使いOptionとして受け取る必要があります。
- move クロージャに取り込んだ値をクロージャの外で使うと E0382 になるmoveを付けたクロージャは、参照する変数の所有権を丸ごと取り込みます。取り込まれた後にクロージャの外側でその変数を使おうとするとE0382エラーになります。
- E0106: missing lifetime specifier の原因と直し方参照を返す関数で、その参照が複数の引数のどちらに由来するのかコンパイラが判断できない場合、E0106エラーになります。ライフタイム注釈を付けて、戻り値の参照がどの引数と同じ生存期間なのかを明示する必要があります。
- E0277: doesn't implement `std::fmt::Display` の原因と直し方自作の構造体を{}(Display)で出力しようとすると、Displayトレイトを実装していない限りE0277エラーになります。デバッグ目的で中身を見たいだけなら、{:?}(Debug)を使う方法もあります。
- E0072: recursive type has infinite size の原因と直し方構造体が自分自身の型を直接フィールドに持つと、サイズが無限になってしまいコンパイルエラーになります。Boxなどのポインタ経由の間接参照を挟むことで、サイズを確定させる必要があります。
- range end index out of range for slice パニックの原因と直し方配列やVecをスライスする際、範囲の終端が要素数を超えているとパニックします。スライス構文v[a..b]は、bが要素数以下であることが前提です。
- ブロック内でのシャドーイングは外側の変数に反映されないif文などのブロックの中でletを使って同じ名前の変数を再宣言(シャドーイング)すると、それはブロック内だけで有効な別の変数になります。ブロックを抜けると、外側の変数は変更されないまま残ります。
- swap_remove は要素の順序を保証しない(remove との違い)Vecのswap_removeは指定位置の要素を削除し、その穴を最後の要素で埋めるため高速ですが、要素の順序が変わります。順序を保ったまま削除したい場合はremoveを使う必要があります。
- byte index is not a char boundary パニックの原因と直し方Rustの文字列はUTF-8のバイト列として保持されており、日本語のようなマルチバイト文字の途中の位置でスライスしようとするとパニックします。文字単位で扱いたい場合はcharsなどのイテレータを使う必要があります。
上級
- already borrowed: BorrowMutError パニックの原因と直し方RefCellは借用規則を実行時にチェックする仕組みです。borrow_mut()で可変借用した値がまだ生きている間に、もう一度borrow_mut()やborrow()を呼ぶとパニックします。
- E0782: trait objects must include the `dyn` keyword の原因と直し方トレイトを直接型として使おうとすると、コンパイル時のサイズが確定できないためエラーになります。トレイトオブジェクトとして扱いたい場合は、dynキーワードを付けてBox<dyn Trait>や&dyn Traitのようにポインタ経由にする必要があります。
- E0597: does not live long enough の原因と直し方ブロックの中で作った値への参照を、そのブロックの外に持ち出そうとするとE0597エラーになります。参照先の値は、参照そのものと同じかそれより長く生存していなければなりません。
- E0004: non-exhaustive patterns の原因と直し方match式は、値が取りうるすべてのパターンを網羅していなければコンパイルできません。一部のケースだけを書いて残りを省略すると、E0004エラーになります。
- as によるダウンキャストは警告なしで値を切り捨てるasによる整数の型変換(ダウンキャスト)は、変換先の型で表現できない値を警告もエラーもなく切り捨てます。300をu8にキャストすると、下位8ビットだけが残り44になります。
- ジェネリック関数に値を渡すと所有権がムーブされ2回使えないジェネリック型Tを所有権ごと受け取る関数に値を渡すと、Copyを実装していない型の場合は所有権がムーブされます。同じ値をもう一度渡そうとするとE0382エラーになります。
- E0284: type annotations needed の原因と直し方parse()のように戻り値の型がジェネリックで、文脈からも型を一意に決められない場合、E0284エラーになります。変数に明示的な型注釈を付けるか、parse::<i32>()のようにturbofish記法で型を指定する必要があります。
- E0507: cannot move out of ... which is behind a shared reference&で借りている構造体のフィールドを、所有権を要求する関数にそのまま渡そうとするとE0507エラーになります。参照の向こう側にある値は借りているだけなので、勝手に持ち出す(ムーブする)ことはできません。