Docsの目次

Resultで失敗を扱う

目次 · 文法 · 関数一覧

Result[T, Error]は成功値Tか失敗Errorを返します。失敗を呼び出し元へ伝えるときはtry、その場で回復したり別の応答にしたりするときはmatchを使います。

このページの目次

失敗を呼び出し元へ返す

次は関数の例です。tryで成功値を取り出し、失敗ならそのErrorをそのまま返します。tryを書く関数自身もResultを返す必要があります。

def read_id(text: view[str]) -> Result[i64, Error]:
    id = try parse_i64(text)
    if id < 1:
        return error("id must be positive")
    return ok(id)

非同期の処理ではvalue = try await operation(...)と書きます。

成功と失敗を分ける

次のコードは、そのまま保存して実行できます。result.nagiにもあります。失敗したら既定値に回復するため、この関数の戻り値は通常のi64にできます。

def number_or(text: str, fallback: i64) -> i64:
    match parse_i64(view(text)):
        case Ok(number):
            return number
        case Err(problem):
            print(error_kind(problem))
            message = error_message(problem)
            assert_true(len(view(message)) > 0)
            return fallback

def main():
    print(number_or("21", 0))
    print(number_or("oops", -1))

result.nagiとして保存したフォルダーで実行します。

nagic run result.nagi

出力は順に21、invalid、-1です。OkとErrは先頭が大文字のパターンです。値を作る関数は小文字のok(...)やerror(...)を使います。

  • case Ok(...)とcase Err(...)を、それぞれ1回ずつ書く。順番はどちらでもよい。
  • 括弧内の名前には成功値・失敗値の型が付く。使わない値はcase Err(_):などと書く。
  • 名前はそのcase内だけで使える。外側で使っている変数名との重複は拒否する。
  • matchは対象のResultを消費する。所有文字列などのpayloadもmoveされる。借用payloadの元データはcase内でも借用中として検査する。
  • 両方のcaseがreturnすれば、関数の全経路で値を返すものとして検査する。

現在のmatchはResultを対象とする文です。値を返すmatch式、nullableのSome / None、ガード、入れ子のパターンは未対応です。Lowでも同じ分岐を使えます。

Errorを調べる・作る・返し直す

書き方 意味
error("理由") 入力の失敗を作る。kindはinvalid
not_found("理由") 対象なしの失敗を作る。kindはnot_found
internal_error("理由") 内部の失敗を作る。kindはinternal
error_kind(problem) kindの名前を所有文字列で取得する
error_message(problem) messageのコピーを所有文字列で取得する
return fail(problem) 元のkindとmessageを保ち、Errorをmoveして返す

Errorを作る関数とfailの成功型は、戻り先や変数の型から決まります。型の文脈がなければResult[unit, Error]です。error_kindとerror_messageはErrorを消費しないため、そのあとでfail(problem)を使えます。messageにはDBなどの内部情報が含まれる場合があります。

HTTPではErrorの種類を次のように変換します。

kind HTTPステータス
invalid 400
not_found 404
busy 503
database / internal 500

DB・内部エラーの500応答は{"error":"internal error"}で、詳細はサーバーのログに出します。Result[T?, Error]の成功値がNoneでも404になります。

入力不正・対象なし・DB失敗と、失敗からの回復を試すにはResult APIサンプルを使ってください。サンプルのテストは、起動したサーバーにリクエストを送り、応答を確認します。

検査とpanicの範囲

直接捨てたResult、awaitしていないFutureは型検査で拒否します。代入したResultを全経路で必ず処理する検査は未完成です。

JSON・DB・入力検査の失敗とpanicは別です。scopeでは子taskのpanicを検出し、Supervisorではworkerのpanicを再起動対象にします。メモリ破壊・process abortの回復機構ではありません。

診断はファイル名、行、該当ソース、理由を表示します。ビルド時も、元の位置を特定できるエラーはNagi・Lowの文や定義の行を先に表示し、生成Rustの詳しい診断を続けます。Rustの修正候補はRust向けなので、そのままNagiへ適用しないでください。手書きRustや位置を特定できない診断はRust側の表示を使います。厳密な列位置や全Rust診断の対応は未実装です。VS Codeの定義ジャンプは元ソースの列位置も扱います。

Nagi 0.1のドキュメントこのページのソース