Code Fix

中級

attempt to subtract with overflow パニックの原因と直し方

符号なし整数(usizeなど)で0から1を引くような演算を行うと、負の値を表現できないため実行時にパニックします。Vecの長さから1を引く処理で、空のVecを渡すと典型的に発生します。

エラーメッセージの読み方

thread 'main' panicked at main.rs:3:22:
main.rs
ファイル名
3
行番号 — 実際にクラッシュした行
22
列番号
panicked
パニック — 実行時に回復不能な状態になったことを示します。tryやResultで捕まえない限り、そのままプロセスが終了します
attempt to subtract with overflow
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  fn main() {
 2      let scores: Vec<i32> = vec![          ];
                                         ^
 3      let last_index = scores.len() - 1;
 4      println!("{}", last_index);
 5  }
thread 'main' panicked at main.rs:3:22: attempt to subtract with overflow

scoresが空だとlen()は0になり、usizeの0から1を引く計算は表現できずパニックします。

直し方: (空)10, 20, 30 にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  fn main() {
 2      let entries: Vec<i32> = vec![    ];
                                       ^
 3      let last_index = entries.len() - 1;
 4      println!("{}", last_index);
 5  }
thread 'main' panicked at main.rs:3:22: attempt to subtract with overflow

usizeは符号なし整数なので負の値を表現できず、0からの引き算はオーバーフローとしてパニックします。

直し方: (空)1, 2 にします。

この問題を解いてみる →

パターン3

 1  fn main() {
 2      let queue: Vec<i32> = vec![       ];
                                      ^
 3      let last_index = queue.len() - 1;
 4      println!("{}", last_index);
 5  }
thread 'main' panicked at main.rs:3:22: attempt to subtract with overflow

空になりうるVecの長さから1を引く処理は、事前に空かどうかをチェックする必要があります。

直し方: (空)7, 8, 9 にします。

この問題を解いてみる →

パターン4

 1  fn main() {
 2      let stack: Vec<i32> = vec![    ];
                                     ^
 3      let last_index = stack.len() - 1;
 4      println!("{}", last_index);
 5  }
thread 'main' panicked at main.rs:3:22: attempt to subtract with overflow

デバッグビルドではusizeのオーバーフローは検出されパニックしますが、原因はコンパイル時には分かりません。

直し方: (空)4, 5 にします。

この問題を解いてみる →

パターン5

 1  fn main() {
 2      let buffer: Vec<i32> = vec![ ];
                                    ^
 3      let last_index = buffer.len() - 1;
 4      println!("{}", last_index);
 5  }
thread 'main' panicked at main.rs:3:22: attempt to subtract with overflow

checked_subのような安全な引き算方法を使えば、パニックせずNoneとして失敗を扱えます。

直し方: (空)1 にします。

この問題を解いてみる →

よくある誤解

「引き算した結果が負になれば、自動的にマイナスの値になるはず」という思い込みは誤りです。usizeのような符号なし整数は負の値を表現できないため、デバッグビルドではオーバーフローとしてパニックします。

まとめ

attempt to subtract with overflow パニックの原因と直し方は中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)