Skip to content
lriki edited this page Jun 28, 2022 · 1 revision

エラーハンドリング

Lumino のエラーの考え方

ロジックエラー (回復不能なエラー)

API(関数)の使い方がそもそも間違っている問題です。

次のようなケースが代表例です。

  • APIに不正な引数を渡す (nullアクセスや範囲外アクセス)
  • オブジェクトの状態によって不正な操作を行った (オブジェクトを構築するためのデータのロード中に、オブジェクトにアクセスしてしまった)
  • 未実装の機能を呼び出した。

Lumino はこの状態を、バグか仕様かに関わらず、アプリケーションがプログラマの想定していなかった状況に陥っている状態(無理に復帰させても、不正なデータがDBに記録されたり、脆弱性の原因となったりする可能性がある)と考えます。 これを検出した場合、Lumino はアサーションハンドラを呼び出した後、ログを記録してアプリケーションをクラッシュさせます。

ユーザーエラー (回復可能なエラー)

アプリケーションのユーザーの誤操作が原因の問題です。

次のようなケースが代表例です。

  • テキストボックスに不正な文字を入力した。
  • インターネットに接続していない状態でファイルをダウンロードしようとした。
  • アプリケーションが開こうとしたファイルを、間違えて消してしまった。

このような問題が発生しうる関数は、戻り値が Result 型となっています。 簡単に言うと処理の成否を表す bool 型のようなもので、対策を講じるべき回復可能なエラーの存在をプログラマに対して明確に示すためのものです。

Result 型

RustのResult に着想を得た機能です。 std::optional のように使用できますが、失敗時のエラー情報の保持や、異なる型のエラーを呼び出し元関数に返すBox機能があります。

典型的な使い方は次のようになります。

Result loadSettings(const Char* filePath) {
    if (!filePath) return err();
    
    ln::IOResult<ln::String> result = ln::FileSystem::readAllText(filePath);
    if (result) {
        // 読み込み成功
        ln::String text = *result;
        std::cout << text;
    }
    else {
        // 読み込み失敗
        return result;
    }
    
    return ok();
}
// 型名が冗長になりやすいため、基本的には auto を使って受け取ったほうが簡単です。
auto result = ln::FileSystem::readAllText(filePath);
if (!result) return result;

// std::optional と同じく * や -> で値にアクセスできますが、より明示的に値の取得を示したい場合 unwrap() も同様に使用できます。
// いずれも、失敗時に呼び出すとロジックエラーとしてクラッシュが発生します。
auto text1 = result.unwrap();

Clone this wiki locally