使用结果有什么好处? [英] What's the benefit of using a Result?
问题描述
我不明白为什么 Result
存在于 Rust 中.我可以看到 Option
是如何有用的,但是使用 Result
似乎只是不必要地使代码复杂化.
I don't understand why Result
exists in Rust. I can see how Option
can be useful, but using Result
just seems to complicate code unnecessarily.
考虑以下示例:
#[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()
来返回结果.
The only thing I can see is that it minorly increases the convenience of function writers, as you can simply call Ok()
and Err()
to return results.
我看到有些人说它可以使用条件,但事实并非如此;您可以使用元组很好地使用条件.(注意——条件"是 Rust 的一个特性,在 1.0 之前被移除)
I've seen some people saying its so you can use conditions, but that's not true at all; you can use conditions perfectly well using tuples. (Note — "conditions" were a feature of Rust that were removed before 1.0)
我也看到有人说 Result
比返回元组的性能更高,但是 Result
是 元组,所以我不明白这是怎么回事.
I've also seen some people saying that Result
is more performant that returning a tuple, but Result
is a tuple, so I don't see how this can be the case.
推荐答案
让我们考虑 Result
的定义:
Let's consider 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
.
Distilled to the bits that matter, it's enum Result<T, E> { Ok(T), Err(E) }
.
那不是元组(T, E)
;相反,它是要么一个T
(OK)或一个E
(错误).
That is not a tuple (T, E)
; rather, it is either a T
(OK) or an E
(error).
如果使用元组 (T, E)
,则必须同时定义 T
和 E
>.对于您的 returns_tuple
,这意味着将 0 定义为一个魔术值并向您的 MyErr
枚举、None
添加一个新变体.None
不是错误;如此建模在语义上是不合理的.由于穷举匹配的要求,它随后也会传播到其他地方.
If you use a tuple (T, E)
, you must define both the T
and the E
. For your returns_tuple
, that meant defining 0 as a magic value and adding a new variant to your MyErr
enumeration, None
. None
is not an error; it is semantically unsound to model it thus. It also then propagates to other places because of the requirement of exhaustive matching.
当您处理更复杂的类型时,定义一个虚拟值可能不太可行或成本更高.作为概括,拥有虚拟值不是一个好的计划.很有可能在某个阶段,您实际上会尝试使用它们.
When you are dealing with more complex types, defining a dummy value may be less feasible or more expensive. As a generalisation, having dummy values is not a good plan. It's far too likely that somewhere down the track you will actually try to use them.
Rust 有一个很好的类型系统,可以让你避免这类问题.
Rust has a good type system which allows you to avoid these sorts of problems.
在我看来你已经错过了 Rust 匹配的力量;事实上,从枚举中获取值的唯一方法是模式匹配;因此,像 Result.ok()
、Result.err()
和 Option.unwrap()
之类的东西都是在模式匹配方面实现的.
It looks to me like you've missed the power of Rust's matching; in fact, the only way to get a value out of an enum is pattern matching; in consequence, things like Result.ok()
, Result.err()
and Option.unwrap()
are implemented in terms of pattern matching.
现在让我们以更好地展示 Rust 的方式编写您的示例.
Now let's write your example in a way that shows Rust in a better light.
#[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"),
}
}
这篇关于使用结果有什么好处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!