使用结果有什么好处?

时间:2014-03-05 03:29:34

标签: rust

我不明白为什么在Rust中存在Result。我可以看到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()即可返回结果。

我见过一些人说它,所以你可以使用条件,但这根本不是真的;你可以使用元组完美地使用条件。 (注意 - “条件”是在1.0 之前删除的Rust的一个特性)

我也看到有些人说Result返回元组的性能更高,但Result 一个元组,所以我看不出这是怎么回事可能就是这样。

2 个答案:

答案 0 :(得分:32)

让我们考虑the definition of 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);相反,它是 一个T(确定)一个E(错误)。

如果您使用元组(T, E),则必须同时定义T E。对于returns_tuple,这意味着将0定义为魔术值,并为MyErr枚举添加新变体NoneNone不是错误;因此,对它进行建模在语义上是不合理的。然后由于需要进行详尽的匹配,它也会传播到其他地方。

当您处理更复杂的类型时,定义虚拟值可能不太可行或更昂贵。作为概括,具有虚拟值并不是一个好的计划。你很可能会在赛道的某个地方尝试使用

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"),
    }
}

答案 1 :(得分:0)

Option 用于表示一个可为空的值,可能有也可能没有,基本上它包装了一个可为空的值并强制您在每次想要访问它时检查可能的空情况。

Result 用于表示易出错操作的结果,例如 IO 操作或网络请求,因为存在失败的可能性,类型系统强制您每次要访问时检查可能的错误情况结果数据。