web-dev-qa-db-ja.com

結果を使用する利点は何ですか?

ResultがRustに存在する理由がわかりません。 Optionがどのように役立つかはわかりますが、Resultを使用すると、コードが不必要に複雑になるようです。

次の例を考えてみましょう。

_#[derive(PartialEq, Eq, Debug)]
enum MyErr {
    None,
    FailOne,
}

fn returns_Tuple() -> (u8, MyErr) {
    // (1, None) // <-- Success path
    (0, MyErr::FailOne)
}

fn returns_result() -> Result<u8, MyErr> {
    // Ok(1) // <-- Success path
    Err(MyErr::FailOne)
}

#[test]
fn test_check_return_values() {
    let x = returns_result();
    if x.is_ok() {
        println!("result: Is OK: {}", x.unwrap()); // <-- Must use unwrap
    } else {
        match x.err().unwrap() { // <-- Again, unwrapping
            MyErr::None => {}, // Required for match
            MyErr::FailOne => println!("result: Failed One"),
        }
    }
}

#[test]
fn test_check_return_values_2() {
    let (y, err) = returns_Tuple();
    match err {
        MyErr::None => println!("Tuple: Is OK: {}", y),
        MyErr::FailOne => println!("Tuple: Failed one"),
    }
}
_

私が見ることができる唯一のことは、結果を返すためにOk()Err()を呼び出すだけでよいので、関数ライターの利便性がわずかに向上することです。

条件を使用できるようにするためにそう言っている人を見たことがありますが、それはまったく真実ではありません。タプルを使用すると、条件を完全にうまく使用できます。 (注—「条件」はRust 1.0より前に削除されたの機能でした)

また、Resultはタプルを返すよりもパフォーマンスが高いと言う人もいますが、Resultisタプルなので、これがどのようにできるのかわかりません。そうである。

24
Doug

考えてみましょう Resultの定義

_/// `Result` is a type that represents either success (`Ok`) or failure
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[must_use]
pub enum Result<T, E> {
    /// Contains the success value
    Ok(T),

    /// Contains the error value
    Err(E)
}
_

重要な部分に蒸留すると、それはenum Result<T, E> { Ok(T), Err(E) }です。

それはタプルではありません_(T, E)_;むしろ、それはどちらかa T(OK)またはE(エラー)。

タプル_(T, E)_を使用する場合は、TEの両方を定義する必要があります。 _returns_Tuple_の場合、これは0を魔法の値として定義し、MyErr列挙型Noneに新しいバリアントを追加することを意味しました。 Noneはエラーではありません。このようにモデル化することは意味的に不健全です。また、徹底的なマッチングが必要なため、他の場所にも伝播します。

より複雑な型を扱う場合、ダミー値を定義することは実行可能性が低いか、より費用がかかる可能性があります。一般化として、ダミー値を持つことは良い計画ではありません。トラックのどこかで実際にそれらを使用しようとする可能性は非常に高いです。

Rustには、この種の問題を回避できる優れた型システムがあります。

Rustのマッチングの力を逃したように私には見えます。実際、列挙型から値を取得する唯一の方法は、パターンマッチングです。その結果、Result.ok()Result.err()Option.unwrap()などがパターンマッチングの観点から実装されます。

それでは、Rustをより適切に示す方法で例を書いてみましょう。

_#[derive(PartialEq, Eq, Debug)]
enum MyErr {
    // Now we don't need that phoney None variant.
    FailOne,
}

fn returns_result() -> Result<u8, MyErr> {
    Err(MyErr::FailOne)
}

#[test]
fn test_check_return_values() {
    match returns_result() {
        Ok(num) => println!("result: Is OK: {}", num),
        Err(MyErr::FailOne) => println!("result: Failed One"),
    }
}
_
36
Chris Morgan