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として返ります。