Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Rust辞典

  1. トップページ
  2. Rust辞典
  3. panic!() / unwrap() / expect() の使い分け

panic!() / unwrap() / expect() の使い分け

Rustのパニック(panic!)は回復不能なエラー時にプログラムを即座に停止させます。一方、『unwrap()』や『expect()』はOptionやResultがNone/Errのときにパニックします。回復可能なエラーと使い分けが重要です。

構文
// panic!: 回復不能なエラーでプログラムを停止します。
panic!("致命的なエラーが発生しました");
panic!("インデックス {} は範囲外です", index);

// unwrap(): None / Err のときにパニックします。
let value = some_option.unwrap();
let result = some_result.unwrap();

// expect(): パニック時のメッセージをカスタマイズします。
let value = some_option.expect("設定ファイルが見つかりません");

// unreachable!(): 到達不可能なコードに使います。
unreachable!("このコードには到達しないはずです");

// todo!(): 未実装の部分に使います(コンパイルは通ります)。
todo!("この機能はまだ実装されていません");

// unimplemented!(): todo! の代替です。
unimplemented!();
パニック系マクロ一覧
マクロ・メソッド概要
panic!("メッセージ")明示的にパニックを起こします。回復不能なエラーに使います。
unwrap()Some(T) / Ok(T) から値を取り出します。None / Err でパニックします。
expect("メッセージ")unwrap() と同様ですが、パニック時のメッセージをカスタマイズできます。
unwrap_or(default)None / Err の場合にデフォルト値を返します(パニックしません)。
unwrap_or_else(|| ...)None / Err の場合にクロージャの結果を返します。
unreachable!()到達不可能なコードパスに使います。実行されるとパニックします。
todo!()未実装コードのプレースホルダーです。実行されるとパニックします。
assert!(condition)条件が偽ならパニックします(テストや前提条件チェックに使います)。
assert_eq!(a, b)a == b でなければパニックします。
サンプルコード
fn divide(a: f64, b: f64) -> f64 {
    // 前提条件のチェックです(内部ロジックの不変条件)。
    assert!(b != 0.0, "除数はゼロ以外にしてください");
    a / b
}

fn first_even(numbers: &[i32]) -> Option<i32> {
    numbers.iter().find(|&&x| x % 2 == 0).copied()
}

fn main() {
    // unwrap(): 確実に値があるとわかっているときに使います。
    let v = vec![1, 2, 3];
    let first = v.first().unwrap();  // Vecが空でないことが明白な場合
    println!("first: {}", first);

    // expect(): エラーメッセージを明確にします。
    let value: Option<i32> = Some(42);
    let n = value.expect("値が設定されていません");
    println!("n: {}", n);

    // unwrap_or(): デフォルト値を使います(パニックしません)。
    let none: Option<i32> = None;
    let safe = none.unwrap_or(0);
    println!("safe: {}", safe);

    // unwrap_or_else(): 動的にデフォルト値を生成します。
    let result: Result<i32, &str> = Err("エラー");
    let val = result.unwrap_or_else(|e| {
        println!("エラーが発生: {}", e);
        -1
    });
    println!("val: {}", val);

    // Option の安全な処理です(if let / ? 演算子が推奨されます)。
    let numbers = vec![1, 3, 5, 4, 7];
    match first_even(&numbers) {
        Some(n) => println!("最初の偶数: {}", n),
        None => println!("偶数がありません"),
    }

    // assert! で前提条件を検証します。
    let result = divide(10.0, 2.0);
    println!("10 / 2 = {}", result);
    assert_eq!(result, 5.0);

    // todo! で未実装をマークします(実行しなければコンパイルは通ります)。
    #[allow(dead_code)]
    fn not_yet_implemented() -> i32 {
        todo!("後で実装します")
    }

    // unreachable! の例です。
    let x = 5;
    let label = match x % 3 {
        0 => "3の倍数",
        1 => "3n+1",
        2 => "3n+2",
        _ => unreachable!("余りは0,1,2のみのはずです"),
    };
    println!("x={}: {}", x, label);
}
概要

パニックと回復可能エラーの使い分け方針:プログラムのバグ(前提条件違反・到達不能コードなど)にはパニック、ユーザー入力や外部環境が原因のエラーにはResult/Optionを使います。

プロダクションコードでは『unwrap()』の多用を避け、できるだけ『?』演算子やパターンマッチでエラーを処理してください。プロトタイプや明らかに安全な場合には使っても構いません。

パニックはスレッドを終了させます。メインスレッドがパニックするとプロセス全体が終了します。並行処理では意図しないパニックが他のスレッドに影響しないよう注意が必要です。

カスタムエラー型の定義は『カスタムエラー型 / thiserror』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。