1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rust エラーハンドリング

Last updated at Posted at 2025-08-16

はじめに

Rust ではプログラムが予期せぬエラーに遭遇した状況を パニック という。

パニックは意図的に panic! で発生させることもできる。

またパニックに陥ったプログラムは復旧することができない。
(厳密には通常、パニックに陥ったスレッドは終了し、プログラム全体も終了する。ただし特殊な仕組みを使えば、スレッドごとにパニックを捕捉して処理を続けることもできる。)

Rust では Result<T, E> を利用することによってパニックを回避することができる。

Result<T, E> の使い方を理解する上で最低限以下の知識が必要になる。

Enum

列挙型とも呼ばれる。

Enum の定義
enum Fruit {
    Apple,
    Banana,
    Orange,
}

列挙子へのアクセスは :: を使用する。

列挙子へのアクセス
enum Fruit {
    Apple,
    Banana,
    Orange,
}

let x: Fruit = Fruit::Apple;
let y: Fruit = Fruit::Banana;
let z: Fruit = Fruit::Orange;

値を保持する列挙子

列挙子は値を持つことができる

列挙子が値を持つ場合
enum Fruit {
    Apple(String),
    Banana(i32),
    Orange(String, i32),
}

let x: Fruit = Fruit::Apple(String::from("apple"));
let y: Fruit = Fruit::Banana(10);
let z: Fruit = Fruit::Orange(String::from("orange"), 20);

列挙子には構造体を持たせることもできる。

列挙子が構造体を持つ場合
enum Fruit {
    Apple { x: i32, y: String },
}

let x: Fruit = Fruit::Apple {
    x: 10,
    y: String::from("apple"),
};

Option<T>

Rust の標準ライブラリには Option<T> という Enum が用意されている。

Option<T> は値が存在するかどうかを表す型である

値があるときは Some(T)、値がないときは None によって表現する。(None は「エラー」ではなく「値が存在しない」ことを意味する)。

Option
enum Option<T> {
    Some(T),
    None,
}
利用例
fn hello(x: i32) -> Option<String> {
    if 0 < x {
        Some(String::from("hello"))
    } else {
        None
    }
}

Result<T, E>

Result<T, E> は処理の成否を表す型である

成功時は Ok(T) を、失敗時は Err(E) を保持する。

Option<T> が「有無」だけを区別するのに対し、Result<T, E> は失敗した理由を E 型で表現することができる。

Result
enum Result<T, E> {
   Ok(T),
   Err(E),
}
利用例
fn hello(x: i32) -> Result<String, i32> {
    if 0 < x {
        Ok(String::from("hello"))
    } else {
        Err(10)
    }
}

match

_ はマッチしないパターンを表す。

match 制御
fn hello(x: i32) {
    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("other"),
    }
}

match では、すべてのパターンが網羅されていない場合にコンパイルエラーが起きる。

コンパイルエラー
fn hello(x: i32) {
    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        // 網羅されていないパターンがあるためコンパイルエラーが発生する
    }
}

これはプログラミングをする上で、コンパイラがパターンチェクを保証してくれるという点で利点として説明されている。

The power of match comes from the expressiveness of the patterns and the fact that the compiler confirms that all possible cases are handled.
パターンの表現力、すべてのケースが処理されていることをコンパイラが保証してくれる点が match の強みである
Rust knows that we didn’t cover every possible case, and even knows which pattern we forgot! Rust doesn’t compile our code until we fix the problem.
すべてのケースが網羅されていない場合、Rust はそのことを知っているし、どのパターンを忘れたかさえも知っている。さらにそれが直るまでは、コンパイルしない。
The match Control Flow Construct

match の戻り値

match 構文の 1 => println!("one"), 部分は arm と呼ばれ、各 arm に紐付けられたコード(=> の右部分)は である。

そのため、マッチしたアームの「式」の結果を match 式の戻り値とすることができる。

match 式の結果を戻り値にする
fn hello(x: i32) -> String {
    match x {
        1 => String::from("one"),
        2 => String::from("two"),
        3 => String::from("three"),
        _ => String::from("other"),
    }
}

let x: String = hello(10);

複数の処理を実行したい場合には {} を使用する。

match 時に複数の処理を実行する
fn hello(x: i32) -> String {
    match x {
        1 => {
            println!("hello");
            String::from("one")
        }
        _ => String::from("other"),
    }
}

マッチしない _ ときに何も処理を実行したくない場合、ユニット型 を返せば良い。

_ 時に () を返す
fn hello(x: i32) {
    match x {
        1 => println!("hello"),
        _ => (),
    }
}

Enum x match

前述の通り Enum は値を持つことができる。

値をもった Enum と match を組み合わせると、match 構文の中で Enum の値を利用することができる。

Enum x match
enum Fruit {
    Apple(String),  // 値を持つ Enum
    Banana,
    Orange,
}

fn hello(x: Fruit)  {
    match x {
        Fruit::Apple(data) => println!("data is {data}"),  // 値に任意の変数名でアクセスできる
        Fruit::Banana => println!("banana"),
        Fruit::Orange => println!("orange"),
    }
}

fn main() {
    hello(Fruit::Apple(String::from("apple")));
}

比較に対して列挙子の値を利用することもできる。

以下の例では Apple(10) にはマッチするのに対して、Apple(11) に対してはマッチしない。

列挙子が持つ値まで含んだマッチング
enum Fruit {
    Apple(i32),  // 値を持つ Enum
    Banana,
    Orange,
}

fn hello(x: Fruit)  {
    match x {
        Fruit::Apple(10) => println!("apple"),  // 特定の値へのマッチ
        Fruit::Banana => println!("banana"),
        Fruit::Orange => println!("orange"),
        _ => (),
    }
}

Option<T>match を組み合わせると以下のようなことができる。

Option x match
fn hello(x: i32) -> Option<i32> {
    if x == 1 { Some(10) } else { None }
}

fn main() {
    match hello(1) {
        None => println!("none"),
        Some(data) => println!("data is {data}"),
    }
}

if x match

match を使った構文で、特定の値かそれ以外かで処理を分けたい場合に、Rust には if let というシンタックスシュガーがある。

if let
enum Fruit {
    Apple(i32), // 値を持つ Enum
    Banana,
    Orange,
}

fn hello(x: Fruit) {
    match x {
        Fruit::Apple(10) => println!("hello"), // 特定の値へのマッチ
        _ => (),
    }
}

fn hello(x: Fruit) {
    if let Fruit::Apple(10) = x {  // 上記のシンタックスシュガー
        println!("hello");
    }
}

上記の例は以下のように通常の if でも表現できるため、メリットが感じられない場合もあるが、処理の中で列挙子が持つ値にアクセスできるなど、より柔軟な処理が可能という利点がある。

通常の if で表現できる場合もある
fn hello(x: Option<i32>) {
    match x {
        Some(10) => println!("hello"),
        _ => (),
    }
}

// if let 構文
fn hello(x: Option<i32>) {
    if let Some(10) = x {
        println!("hello");
    }
}

// 通常の if 文
fn hello(x: Option<i32>) {
    if x == Some(10)  {
        println!("hello");
    }
}
if let の方が柔軟性が高い
fn hello(x: Option<i32>) {
    match x {
        Some(data) => println!("data is {data}"),
        _ => (),
    }
}

// if let 構文なら表現できる
fn hello(x: Option<i32>) {
    if let Some(data) = x {
        println!("data is {data}")
    }
}

// 通常の if 文では表現できない(コンパイルエラー)
fn hello(x: Option<i32>) {
    if x == Some(data) {
        println!("data is {data}")
    }
}

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?