LoginSignup
10
3

More than 5 years have passed since last update.

OptionをResultにする

Last updated at Posted at 2017-11-11

この記事は入門向けの記事になっています。

Rustが進化して行くに連れて、バージョン1以降になってからも変化がありました。個人的にその変化の一つが ?オペレータの登場です。

fn foo() -> Result<(), String> {
    Err("error".to_owned())?;
    println!("no print");
    Ok(())
}
println!("{:?}", foo());

このオペレータは、try!マクロと同様の動きをします。Rustの多くのプログラマは、このオペレータが登場する前にtry!マクロを活用していました。これからは?が多く使われることでしょう。

他の言語では、? はOptionalとして扱われるケースが多いため、Rustの場合は例外時にreturnされることと、OptionではなくResultであることに注意が必要です。

Option型は ? が使えない

さて、ここで本題に入ります。Rustのcrateによっては、ResultではなくOptionで結果を返すライブラリも多くあります。Optionの場合は、? を使うことが出来ないため、Resultに変換する必要があります。

追記(2018/03/05) 使えるようになっています。

ここから先にいくつか悪い例を紹介し、最後に良い例を紹介します。

matchで変換

fn foo() -> Result<(), String> {
    let opt: Option<String> = None;
    match opt {
        Some(s) => Ok(s),
        None => Err("error".to_owned())
    }?;
    println!("no print");
    Ok(())
}
println!("{:?}", foo());

型でマッチさせたあとにResultを作っています。ちょっと長いです。

unwrap系(動かない)

fn test() {
    fn foo() -> Result<(), String> {
    let opt: Option<String> = None;
    opt.unwrap_or(Err("error".to_owned()))?;
    println!("no print");
    Ok(())
}
println!("{:?}", foo());

こちらは、 expected struct `std::string::String`, found enum `std::result::Result` が発生し失敗します。
unwrap系は、成功した場合、self を返すため、型がどうしてもOptionになってしまいます。

ok_or

fn foo() -> Result<(), String> {
    let opt: Option<String> = None;
    opt.ok_or("error".to_owned())?;
    println!("no print");
    Ok(())
}
println!("{:?}", foo());

Optionには、ok_or<E>(self, err: E) があり、selfOption<T> から Result<T, E> に変換されて返されます。OptionはErrを持っていないため、Resultに変換する際に引数をErrとして渡しているところがポイントです。

OptionをResultに変換する場合は、ok_or を使うとスッキリ書くことが出来ます。他にも、ファンクションが渡せる ok_or_else があります。

10
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
3