メインコンテンツにスキップ
モジュール 7 · レッスン 2 / 2コース内の 14/14~15 min
モジュールのレッスン (2/2)

エラー処理と ?オペレーター

Rust の哲学では、プログラムがコンパイルされる前に、エラーの可能性を明示的に認識し、それらを処理するコードを構築することを推奨しています。

Rust のエラーは、回復不可能なエラー (panic! マクロを介して即時終了を引き起こす) と 回復可能なエラー (Result<T, E> タイプを使用して管理される) の 2 つの主なカテゴリに分類されます。


結果<T, E> タイプとパターン マッチング

ほとんどの回復可能なエラーは、次のように定義された列挙型である Result<T, E> タイプを返します。

Rust
enum Result<T, E> {
    Ok(T),
    Err(E),
}

パターン マッチングを使用して結果を検査できます。

Rust
use std::fs::File;

fn main() {
    let greeting_file_result = File::open("hello.txt");

    let greeting_file = match greeting_file_result {
        Ok(file) => file,
        Err(error) => panic!("Problem opening the file: {:?}", error),
    };
}

? 演算子によるエラーの伝播

関数を実装するとき、関数内で直接エラーを処理するのではなく、呼び出し元にエラーを返し、呼び出し元が何をすべきかを決定できるようにしたいことがよくあります。このプロセスは エラー伝播 と呼ばれます。

Rust は、エラーを伝播するための構文上のショートカットとして ? 演算子を提供します。 Result の値が Ok の場合、式によって Ok の内部値が返されます。 Err の場合、return Err(...) を使用したかのように、現在の関数全体から Err エラーが返されます。

Rust
use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    let mut username_file = File::open("username.txt")?;
    let mut username = String::new();
    username_file.read_to_string(&mut username)?;
    Ok(username)
}

[!重要] ? 演算子は、適用される値と互換性のある型 (通常は Result、Option、または FromResidual を実装する型) を返す関数でのみ使用できます。


カスタムエラー

std::fmt::Display 特性 (およびオプションで std::error::Error) を実装することで独自のカスタム エラー タイプを定義し、人間が判読できるエラー表現を提供できます。

Rust
use std::fmt;

#[derive(Debug)]
struct MyError {
    details: String,
}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error: {}", self.details)
    }
}

impl std::error::Error for MyError {}

自分で試してみてください

演習 1: ? を使用してファイルを読み取るオペレーター

運動#rust.m7.l2.e1
試行回数: 0読み込み中…

? を使用するように read_username_from_file 関数を完了します。ファイルを開いてその内容をユーザー名文字列に読み取ることによって生成されたエラーを伝播するオペレーター。

エディターを読み込み中…
ヒントを表示

エラーを伝播するには、「File::open(...)」と「username_file.read_to_string(...)」の後に「?」文字を追加します。

3 回の試行後に解決策が利用可能になります

演習 2: 数値を解析して 2 倍にする

運動#rust.m7.l2.e2
試行回数: 0読み込み中…

文字列参照 &str を受け入れ、Result<i32, std::num::ParseIntError> を返す parse_and_double という名前の関数を作成します。関数は、val.parse::<i32>() と ? を使用して文字列を解析する必要があります。解析エラーを伝播し、成功すると、Ok でラップされた 2 倍の値を返します。

エディターを読み込み中…
ヒントを表示

`val.parse::<i32>()?` を使用して文字列を解析し、エラーを伝播し、`Ok(num \* 2)` を返します。

3 回の試行後に解決策が利用可能になります

演習 3: カスタム エラーの定義

運動#rust.m7.l2.e3
試行回数: 0読み込み中…

CustomError という名前の空の構造体を定義します。 fmt メソッドのエラー メッセージとして「Si e verificato un errore Personalizzato」を記述して、std::fmt::Display 特性を実装します。

エディターを読み込み中…
ヒントを表示

`struct CustomError;`を宣言し、`fmt`メソッド内に`write!(f, "Si e verificato un errore Personalizzato")`を書くことでDisplayを実装します。

3 回の試行後に解決策が利用可能になります