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
はタプルを返すよりもパフォーマンスが高いと言う人もいますが、Result
isタプルなので、これがどのようにできるのかわかりません。そうである。
考えてみましょう 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)
_を使用する場合は、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"),
}
}
_