導入
ファイルが開けない、数値に変換できない——処理は失敗します。多くの言語は「例外(try/catch)」で扱いますが、Rust には例外がありません。代わりに、失敗を Result 型という値で返します。「成功か失敗か」を、Option と同じく型で明示するのです。
説明
Result<T, E> は標準ライブラリの enum です。
enum Result<T, E> {
Ok(T), // 成功(中身は成功値 T)
Err(E), // 失敗(中身はエラー情報 E)
}
失敗しうる処理は、この Result を返します。中身を使うには、Option と同様に Err の場合を必ず考えさせられます。
fn main() {
// 文字列 → 数値の変換は失敗しうる → Result を返す
let a: Result<i32, _> = "42".parse::<i32>();
let b: Result<i32, _> = "abc".parse::<i32>();
match a {
Ok(n) => println!("成功: {n}"),
Err(e) => println!("失敗: {e}"),
}
// よく使うメソッド
let n = "10".parse::<i32>().unwrap_or(0); // 失敗なら 0
println!("{n}");
}
// 自分でエラーを返す関数
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("0では割れません")) // 失敗を Err で返す
} else {
Ok(a / b) // 成功を Ok で返す
}
}
"42".parse::<i32>()… 変換は失敗しうるのでResultを返す。Ok(42)かErr(...)。matchでOk/Errを分け、それぞれ処理します。「失敗を無視してそのまま使う」ことは型的にできません。unwrap_or(既定)… 失敗時の既定値。手軽ですが、失敗を握りつぶすので使いどころに注意。unwrap()… 成功なら中身、失敗ならパニックして停止。手早い試作やテストでは便利ですが、本番コードでは避け、ちゃんとErrを処理します。
エラーが「戻り値の型」に現れるので、関数のシグネチャを見るだけで「これは失敗しうる処理だ」と分かります。例外のように「どこから飛んでくるか分からない」ことがなく、失敗の扱いがコード上で追跡できるのが Rust 流です。
試すには
"abc".parse::<i32>().unwrap() はパニックします。match や unwrap_or で Err を処理すれば安全に扱えます。「失敗も普通の値」という感覚——Result を受け取ったら開ける——を掴みましょう。次のレッスンで、この処理をもっと簡潔にする ? を学びます。