RustでOptionをResultに変換
RustでOption
をResult
に変換するにはok_or
, ok_or_else
を使うか、anyhowライブラリを使う。関数内にOption
とResult
が混在している場合、Option
をResult
に変換することでどちらも呼び出し元に委譲できるようになる。
anyhowの方が簡単。anyhowの基本的な使い方については以下の記事を参照。
- 関連記事: Rust, anyhowによる基本的なエラー処理
ok_or, ok_or_elseでOptionをResultに変換
ok_or
でOption
をResult
に変換できる。
ベクタの可変参照を受け取り、pop
で末尾の要素を取り出す処理を例とする。pop
はOption
を返す(ベクタが空のときNone
)。
?
演算子で呼び出し元に委譲する。
fn pop_ok_or(v: &mut Vec<&str>) -> Result<String, &'static str> {
let s = v.pop().ok_or("Vector is empty")?;
Ok(String::from(s))
}
let mut v = vec!["10", "20"];
assert_eq!(pop_ok_or(&mut v).unwrap(), "20");
let mut v = vec![];
assert_eq!(pop_ok_or(&mut v).unwrap_err(), "Vector is empty");
ここでは、簡単のため、文字列リテラルをそのままエラーとして返している。また、返り値に対してunwrap
やunwrap_err
で値やエラーを取り出して確認しているが、実際のプログラムでは適切なエラー処理を行えばよい。以降の例も同じ。
上の例のように、関数内にOption
を返す処理しかない場合はOption
をResult
に変換する意味はない。
関数内にOption
とResult
が混在している場合にエラー型を独自に定義して対応する例などがRust By Exampleで紹介されている。
anyhowを使ってOption
とResult
に対応する例は後述。
ok_orとok_or_else
ok_or
は先行評価で、ok_or_else
は遅延評価。関数の結果を渡すような場合、ok_or_else
の使用が推奨されている。
例えば、ok_or(format!(...))
ではなくok_or_else(|| format!(...))
。ok_or
は常にformat!
が実行されてしまうが、ok_or_else
だとNone
のときのみformat!
が実行される。|| format!(...)
は引数なしのクロージャ。
*_or
と*_or_else
との違いについては以下の記事を参照。
anyhowでOptionをResultに変換
anyhowを使うとOption
をanyhow::Result
に変換できる。None
もResult
のエラーも?
演算子で呼び出し元に委譲できるようになる。
本記事のサンプルコードにおけるanyhowのバージョンは以下の通り。
anyhow = "1.0"
use
宣言は以下の通り。
use anyhow::{Context, Result};
anyhow::Context
トレイトをインポートすることで、Result
およびOption
でcontext
, with_context
メソッドが使えるようになる。
ベクタの可変参照を受け取り、pop
で末尾の要素を取り出し、parse
で数値に変換する関数を例とする。pop
はベクタが空のときNone
を返し、parse
は変換できないときエラーを返す。
fn pop_parse_anyhow(v: &mut Vec<&str>) -> Result<i32> {
let s = v.pop().context("Vector is empty")?;
let i = s.parse::<i32>()?;
Ok(i)
}
let mut v = vec!["10", "20"];
assert_eq!(pop_parse_anyhow(&mut v).unwrap(), 20);
let mut v = vec![];
assert_eq!(
pop_parse_anyhow(&mut v).unwrap_err().to_string(),
"Vector is empty"
);
let mut v = vec!["abc", "xyz"];
assert_eq!(
pop_parse_anyhow(&mut v).unwrap_err().to_string(),
"invalid digit found in string"
);
pop
のNone
もparse
のエラーも呼び出し元に委譲できている。
なお、ok_or
とok_or_else
のように、context
は先行評価でwith_context
は遅延評価。詳細は以下の記事を参照。
- 関連記事: Rust, anyhowによる基本的なエラー処理