この疑問符演算子は何についてですか?


回答:


144

お気づきかもしれませんが、Rustには例外はありません。パニックが発生しますが、機能が制限され(構造化された情報を伝達できません)、エラー処理に使用することはお勧めしません(回復不能なエラーを対象としています)。

Rustでは、エラー処理はを使用しResultます。典型的な例は次のとおりです。

fn halves_if_even(i: i32) -> Result<i32, Error> {
    if i % 2 == 0 {
        Ok(i / 2)
    } else {
        Err(/* something */)
    }
}

fn do_the_thing(i: i32) -> Result<i32, Error> {
    let i = match halves_if_even(i) {
        Ok(i) => i,
        Err(e) => return Err(e),
    };

    // use `i`
}

これは素晴らしい理由です:

  • コードを書くとき、誤ってエラーに対処することを忘れることはできません。
  • コードを読むと、ここでエラーが発生する可能性があることがすぐにわかります。

ただし、非常に冗長であるという点で理想的とは言えません。これが疑問符演算子の?出番です。

上記は次のように書き直すことができます。

fn do_the_thing(i: i32) -> Result<i32, Error> {
    let i = halves_if_even(i)?;

    // use `i`
}

これははるかに簡潔です。

?ここで行うことは同等ですmatch上記のステートメント。つまりResult、OKの場合は解凍し、そうでない場合はエラーを返します

少し魔法ですが、エラー処理には定型文を削減するための魔法が必要です。例外とは異なり、どの関数呼び出しがエラーになるかどうかがすぐにわかり?ます。

魔法の一例は、これが次の場合にも機能することですOption

// Assume
// fn halves_if_even(i: i32) -> Option<i32>

fn do_the_thing(i: i32) -> Option<i32> {
    let i = halves_if_even(i)?;

    // use `i`
}

これは、(不安定な)Try特性によって強化されています。

参照:


5
答えを少し拡張できればいいのですが、たとえば、関数の戻り値の型は、「アンラップ」しようとしている型と一致する必要があることを話し合ってください。たとえば、ResultまたはOption
hellow

@hellowまったく新しい質問にしたほうがいいと思います
Paul Razvan Berg

2

これは、回復可能なエラータイプResult <T、E>のエラー伝播用です。結果をアンラップし、内部値を提供します。

エラーの場合を処理するのではなく、それを呼び出し元のコードに伝播し、OKの場合のみを処理します。利点は、多くの定型文が不要になり、関数の実装が簡単になることです。


.unwrap()エラーが発生した場合にパニックになる実際の問題と混同しないでください。
ヨルダン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.