我不明白为什么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{ // 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
是一个元组,所以我不明白这是怎么回事.
让我们考虑以下定义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
(OK)或一个E
(错误).
如果你使用一个元组(T, E)
,则必须同时定义T
和的E
.对于你来说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"),
}
}