Result<T, E>
は処理が無事完了したかを表現する為の型です。正常に終了した場合Ok<T>
、何かしらエラーが起きた場合Err<E>
を返します。
let ok: Result = Ok(33);
let err: Result = Err("fatal error");
Result<T, E>
はモジュールなどに合わせてエイリアス化されている事が多いです。エイリアスにはtype
を使います。
enum FooError {
AError,
BError,
}
type FooResult = Result;
? 演算子
Result
を返す関数呼び出しの後ろに?
を置くと、Ok<T>
の時は::unwrap
のようにT
を返しますが、Err<E>
が返却された時は即時return
になります。
fn return_ok<'a>() -> Result<&'a str, &'a str> {
Ok("foo")
}
fn scope<'a>() -> Result<&'a str, &'a str> {
let foo = return_ok()?;
println!("{}", foo);
Ok(foo)
}
fn main() {
#[allow(unused_must_use)]
scope();
}
return_ok
はResult
型を返す為だけの関数で、scope
は単にそれを実行する為の関数です。scope
を用意した理由は、?
は戻り値がResult
な関数の中でしか使えません。
また?
はErr<E>
な時、単にそれを返すのではなくFrom::from
にE
を渡して実行した結果を返します。なので以下のようにエラー列挙型にまとめるといった事ができます。
struct FooError;
struct BarError;
#[derive(Debug, PartialEq, Eq)]
enum AError<'a> {
FooError(&'a str),
BarError(&'a str),
}
impl<'a> From for AError<'a> {
fn from(_error: FooError) -> Self {
AError::FooError("FooError")
}
}
impl<'a> From for AError<'a> {
fn from(_error: BarError) -> Self {
AError::BarError("BarError")
}
}
fn return_err<'a>() -> Result<&'a str, FooError> {
Err(FooError)
}
fn scope<'a>() -> Result<&'a str, AError<'a>> {
let _ = return_err()?;
unreachable!();
}
fn main() {
assert_eq!(scope().unwrap_err(), AError::FooError("FooError"));
}
return_err
は必ずエラーを返す関数です。impl<'a> From<FooError> for AError<'a>
によってFooError
からAError
に変換できるようにしてる為、この場合AError::FooError
がE
として返ります。