【Rust】Rust ~ Error handling(Result型 / ?演算子) ~

◾️はじめに

https://dk521123.hatenablog.com/entry/2025/11/30/222255
https://dk521123.hatenablog.com/entry/2025/12/01/223443

の続き。

「Rustには class がない」「Rustには null がない」の続きで、
今回は、「Rustには Exception / Try-catch がない」って話。

目次

【0】Rustには Exception / Try-catch がない
 1)Rustには Exception がない
 2)Rustには Try-catch がない
【1】Panic(パニック)
【2】Result型
【3】? 演算子 (Try Operator)
 1)サンプル
 2)Option型で使用する場合

【0】Rustには Exception / Try-catch がない

* Rust は、Javaのようなプログラムと比較した場合
 「エラー・例外」に対する考えが、根本的に異なる
 => 故に、Error handlingに関する考え方も異なる
 => 【1】Panic(パニック) を参照

1)Rustには Exception がない

* Javaのような「例外 (Exception)」という概念は基本的にない
 => 代わりに、Panic(パニック)という別の概念がある

2)Rustには Try-catch がない

* Rust には、Javaなどの Try-catch がない
 => 代わりに、Result型(Ok/Err)および ? 演算子 (Try Operator)で
  エラーハンドリングする
 => 【2】Result型 / 【3】? 演算子 (Try Operator) を参照

【1】Panic(パニック)

* Rustは、「エラーは予期されるもの」 と 「パニックは予期しないバグ」 
 の2種類に問題を明確に分類し、処理方法を分けている。

[1] 予期されるエラー (Recoverable Errors)

* 例:ファイルが見つからない、ネットワーク接続がタイムアウトした。
* プログラムが回復できる可能性があるため、
 Result<T, E> 型を使って値として返され、
 呼び出し元で明示的に処理される。これがRustのエラー処理の主流。

予期しないバグ (Unrecoverable Errors)

* 例:配列の境界外アクセス、メモリ破損。
* プログラムの整合性が壊れたことを意味し、回復不可能であるため、
 Panicで対処される。
* Rustの Panic(パニック) は、
 Javaの非検査例外 (Unchecked Exception) に近いイメージ

【2】Result型

* Scala の Either型に近い
 => 「成功した (Ok) 」、もしくは、「なぜ失敗したのか (Err)」が格納されている

Scala ~ 基本編 / Either型 ~
https://dk521123.hatenablog.com/entry/2023/08/02/132315

// std::io::Result<T> は、実際には Result<T, std::io::Error> の別名
pub enum Result<T, E> {
    Ok(T), // 成功した値 (ここではファイルの内容)
    Err(E), // エラー情報 (ここではI/Oエラー)
}

【3】? 演算子 (Try Operator)

* Result 型(または Option 型)の値の直後につけて使用
 => 例: let num = text.parse::<i32>()?;

Ok の場合

* num に値が入る

Err の場合

* そのまま呼び出し元に返す

1)サンプル

use std::num::ParseIntError;

fn double_string(text: &str) -> Result<i32, ParseIntError> {
    let num = text.parse::<i32>()?; // ★ここに注目★
    Ok(num * 2)
}

fn main() {
    match double_string("10") {
        // 成功: 2倍の結果は 20 です。
        Ok(result) => println!("成功: 2倍の結果は {} です。", result),
        Err(e) => println!("失敗: {:?}", e),
    }

    // Parseを失敗させる
    match double_string("hello") {
        Ok(result) => println!("成功: 2倍の結果は {} です。", result),
        // 失敗: パースエラーが発生しました -> ParseIntError { kind: InvalidDigit }
        Err(e) => println!("失敗: パースエラーが発生しました -> {:?}", e),
    }
}

2)Option型で使用する場合

* Result型だけでなく、Option型で使用可能

サンプル

fn demo_for_option(value: Option<i32>) -> Option<i32> {
    let v = value?;
    Some(v)
}

fn main() {
    match demo_for_option(Some(10)) {
        Some(result) => println!("成功: 2倍の結果は {} です。", result), // こちらが実行
        None => println!("失敗: Noneが返されました。"),
    }

    match demo_for_option(None) {
        Some(result) => println!("成功: 2倍の結果は {} です。", result),
        None => println!("失敗: Noneが返されました。"), // こちらが実行
    }
}

関連記事

Rust ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/04/22/234808
Rust ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2025/11/26/224648
Rust ~ 変数 / データ型 ~
https://dk521123.hatenablog.com/entry/2025/12/05/000647
Rust ~ 保有権 ~
https://dk521123.hatenablog.com/entry/2023/05/04/213726
Rust ~ mod ~
https://dk521123.hatenablog.com/entry/2025/11/29/221911
Rust ~ struct/impl/trait ~
https://dk521123.hatenablog.com/entry/2025/11/30/222255
Rust ~ Option型 ~
https://dk521123.hatenablog.com/entry/2025/12/01/223443
Rust ~ Axum / 入門編 ~
https://dk521123.hatenablog.com/entry/2023/09/02/224707
Rust ~ Axum / REST ~
https://dk521123.hatenablog.com/entry/2025/11/27/145159