Result<T, E> のよく使うメソッドを書いてみる
前回 は Result<T, E> の基本的な使い方と bool に変換するメソッドと中身を取り出すメソッドについて書きました。
今回はよく使うメソッドを書いてみます。以前 Option<T> のメソッドについて書いたのだけど、それと似た感じになってしまいそうなので、よく使うものに絞ってみます。
Result<T, E> を Option<T> / Option<E> にする (中身があれば取り出す) メソッド
ok と err 。 ok は Ok のときに Some を、 err は Err のときに Some を返します。
Result<T, E> でなく Option<T> で十分(エラーの詳細が不要)なときに ok だけ使っているように思います。 err はたぶんあまり使っていない……はず。
let r: Result<i32, &str> = Ok(123);
assert_eq!(r.ok(), Some(123));
let r: Result<i32, &str> = Err("Error!");
assert_eq!(r.ok(), None);
Result<T, E> を Result<U, E> にする (中身を置き換える) メソッド
map 。さすがによく使います。↓の例のようにクロージャを指定することもあるけど、関数やメソッドを指定することも多いです。 .map(Into::into) みたいな形。
let r: Result<i32, &str> = Ok(123);
assert_eq!(r.map(|i| i * 2), Ok(246));
let r: Result<i32, &str> = Err("Error!");
assert_eq!(r.map(|i| i * 2), Err("Error!"));
Result<T, E> を Result<T, F> にする (中身を置き換える) メソッド
map_err 。 map の Err 側のためのもの。 Error の読み替えは多い。
これはドクターメイト株式会社における Error の運用 (定義の仕方) によるものもありそうです。わりと細かい単位で Error を定義しておくようにしているのと、 From をあえて実装しなかったりします。このあたりの運用についてはまた別タイミングで書くかもしれません。
Result<T, E> を Result<&T, &E> や Result<&<T as Deref>::Target, &E> にする (中身を参照にする) メソッド
as_ref / as_deref 。前述の .map(X::method) のような場合に参照を取るケースが多いです。そういうときにしれっと挟みます。
let r: Result<i32, &str> = Ok(123);
assert_eq!(r.as_ref().map(i32::to_string), Ok("123".to_owned()));
&r としてしまうと &Result<T, E> になってしまうので、 as_ref で Result<&T, &E> にしたい、というわけですね。感じですね。
余談: transpose を意外と使わない
Option<T> のときに書いた transpose 。 Result の transpose は意外と使わないです。 Option<Result<T, E>> から Result<Option<T>, E> はよく使うんですけど、 Result<Option<T>, E> から Option<Result<T, E>> はそんなに使っていないです。
おそらく、ほとんどが Result で ? 演算子を使っているからで、 Result を外側に持っていきたいからだと思います。
おわりに
Result<T, E> のリファレンスを見ながら、よく使うメソッドを書いてみました。特に「これは!」というものがなかったのですが、皆さんはどうですかね。
結局 ? 演算子にはほとんど触れなかったですね。
追記: 次回『 Error トレイトの定義を確認してみた』を書きました。
Discussion