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パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。