Rust:
エラー処理

どのように:

Rustは主に2つの方法でエラーを処理します:回復可能エラーと回復不可能エラーです。両方について見てみましょう。

回復可能エラーではResult<T, E>を使用します:

use std::fs::File;

fn open_file(filename: &str) -> Result<File, std::io::Error> {
    let f = File::open(filename);
    
    match f {
        Ok(file) => Ok(file),
        Err(e) => Err(e),
    }
}

fn main() {
    match open_file("hello.txt") {
        Ok(_file) => println!("ファイルのオープンに成功しました。"),
        Err(_e) => println!("ファイルを開くのに失敗しました。"),
    }
}

出力はhello.txtの状態に応じて「ファイルのオープンに成功しました。」または「ファイルを開くのに失敗しました。」のどちらかです。

回復不可能エラーの場合にはpanic!を使います:

fn main() {
    // これはファイルが存在しないため、プログラムをパニックさせるでしょう。
    let _f = File::open("nowhere.txt").unwrap();
}

実行すると、パニックメッセージが表示されます。プログラムは即座に停止します。

深掘り

歴史的に見て、プログラミングにおけるエラーハンドリングは混乱をきたしていました。Rustは、回復可能エラーと回復不可能エラーの明確な区別を持っており、それを正しく取り入れています。

回復可能エラー用のResult列挙型は明示的です。OkまたはErrのバリアントを処理します。unwrap()expect()のようなメソッドもありますが、それらはpanic!に繋がり得る速攻で汚い近道です。

panic!は、本当に悪いことが起こったとRustが叫んでいる方法であり、対処不可能です。プログラムの実行を即座に停止する、回復不可能なエラーのようなものです。Rustにおけるパニックは、配列の境界外へのインデックス付けのような、処理を予期していないバグでしばしば感じられます。

エラーを処理するためにResultを返すことは、エラーを処理することを期待している場合に推奨されます。それは慣用的なRustであり、つまりRust開発者が物事を行う方法として合意したものです。エラーが単にNoneの代わりにSome(T)である場合のOption<T>もあります。恐れることなく、予期せぬ状況を期待することについてです。

代替手段?もちろん、より多くの機能や使いやすさのために他のエラーハンドリングクレートを使用することもできます。たとえば、シンプルなエラーハンドリングにはanyhowを、ライブラリコードのエラーにはthiserrorを使用します。

参照

さらに深く掘り下げたいですか?次を参照してください:

良いエラーハンドリングは単にコーティングすることだけではありません。それは、コードの使用者に対する思いやりです。ハッピーコーディング!