※ 項目の末尾の *
は Result あるいは Option にしかないメソッドであることを表す。
概要
Rust には様々な標準ライブラリが用意されています。
その中には Result 型や Option 型といった便利な型があります。
これらにはいくつかのメソッドが用意されており、エラーや None の値を簡潔かつ適切に処理することができます。
この記事では Result 型と Option 型のいくつかのメソッドについてまとめて、列挙していきます。
std::Result
doc.rust-lang.org
Rust には Result 型と言われるものがあり、これは関数が成功するか失敗するかの結果を表現する列挙型です。
一般的には、成功時には Ok 値を、失敗時には Err 値を返します。
Result 型は、 Rust のエラーハンドリングにおいて非常に重要な役割を担っています。
pub enum Result<T, E> {
Ok(T),
Err(E),
}
map
Ok
の場合には関数を適用して Err
の場合にはそのままにして Result
を返す
pub fn map<U, F>(self, op: F) -> Result<U, E>
where
F: FnOnce(T) -> U,
Example
let line = "1\n2\n3\n4\n";
for num in line.lines() {
match num.parse::<i32>().map(|i| i * 2) {
Ok(n) => println!("{n}"),
Err(..) => {}
}
}
map_err*
Ok
の場合にはそのままにして Err
の場合には関数を適用して Result
を返す
pub fn map_err<F, O>(self, op: O) -> Result<T, F>
where
O: FnOnce(E) -> F,
Example
fn stringify(x: u32) -> String { format!("error code: {x}") }
let x: Result<u32, u32> = Ok(2);
assert_eq!(x.map_err(stringify), Ok(2));
let x: Result<u32, u32> = Err(13);
assert_eq!(x.map_err(stringify), Err("error code: 13".to_string()));
map_or
Ok
の場合には関数を適用して Err
の場合にはデフォルト値を返す
pub fn map_or<U, F>(self, default: U, f: F) -> U
where
F: FnOnce(T) -> U,
Example
let x: Result<_, &str> = Ok("foo");
assert_eq!(x.map_or(42, |v| v.len()), 3);
let x: Result<&str, _> = Err("bar");
assert_eq!(x.map_or(42, |v| v.len()), 42);
map_or_else
Ok
の場合には関数を適用して Err
の場合にはフォールバック関数を適用する
pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
where
D: FnOnce(E) -> U,
F: FnOnce(T) -> U,
Example
let k = 21;
let x : Result<_, &str> = Ok("foo");
assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3);
let x : Result<&str, _> = Err("bar");
assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42);
unwrap
Ok
の場合には値をそのまま返して Err
の場合にはパニックを起こす
pub fn unwrap(self) -> T
where
E: Debug,
Example
let x: Result<u32, &str> = Ok(2);
assert_eq!(x.unwrap(), 2);
let x: Result<u32, &str> = Err("emergency failure");
x.unwrap();
unwrap_err*
Ok
の場合にはパニックを起こして Err
の場合には値をそのまま返す
pub fn unwrap_err(self) -> E
where
T: Debug,
Example
let x: Result<u32, &str> = Ok(2);
x.unwrap_err();
let x: Result<u32, &str> = Err("emergency failure");
assert_eq!(x.unwrap_err(), "emergency failure");
unwrap_or
Ok
の場合には値をそのまま返して Err
の場合には引数の値をデフォルト値として返す
pub fn unwrap_or(self, default: T) -> T
Example
let default = 2;
let x: Result<u32, &str> = Ok(9);
assert_eq!(x.unwrap_or(default), 9);
let x: Result<u32, &str> = Err("error");
assert_eq!(x.unwrap_or(default), default);
unwrap_or_else
Ok
の場合には値をそのまま返して Err
の場合には引数で受けたクロージャの返り値を返す
pub fn unwrap_or_else<F>(self, op: F) -> T
where
F: FnOnce(E) -> T,
Example
fn count(x: &str) -> usize { x.len() }
assert_eq!(Ok(2).unwrap_or_else(count), 2);
assert_eq!(Err("foo").unwrap_or_else(count), 3);
unwrap_or_default
Ok
の場合には値をそのまま返して Err
の場合には Ok
の型のデフォルト値を返す
pub fn unwrap_or_default(self) -> T
where
T: Default,
Example
let good_year_from_input = "1909";
let bad_year_from_input = "190blarg";
let good_year = good_year_from_input.parse().unwrap_or_default();
let bad_year = bad_year_from_input.parse().unwrap_or_default();
assert_eq!(1909, good_year);
assert_eq!(0, bad_year);
and_then
Ok
の場合には関数を呼び出して Err
の場合には値をそのままにして Result
を返す
Ok
型が返ってくるmap
と異なり、関数の返り値も Result
になっている
pub fn and_then<U, F>(self, op: F) -> Result<U, E>
where
F: FnOnce(T) -> Result<U, E>,
Example 1
fn sq_then_to_string(x: u32) -> Result<String, &'static str> {
x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")
}
assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));
assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));
assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));
Example2: Err
を返すかもしれないメソッドチェーンの操作内で用いられる
use std::{io::ErrorKind, path::Path};
let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());
assert!(root_modified_time.is_ok());
let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());
assert!(should_fail.is_err());
assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
or_else
Ok
の場合には値をそのままにして Err
の場合には関数を呼び出して Result
を返す
Err
型が返ってくる map_err
と異なり、関数の返り値も Result
になっている
pub fn or_else<F, O>(self, op: O) -> Result<T, F>
where
O: FnOnce(E) -> Result<T, F>,
Example
fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
fn err(x: u32) -> Result<u32, u32> { Err(x) }
assert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));
assert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));
assert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));
assert_eq!(Err(3).or_else(err).or_else(err), Err(3));
ok
Result<T, E>
を Option<T>
に変換する
Err
は潰れて None
になる
pub fn ok(self) -> Option<T>
Example
let x: Result<u32, &str> = Ok(2);
assert_eq!(x.ok(), Some(2));
let x: Result<u32, &str> = Err("Nothing here");
assert_eq!(x.ok(), None);
err
Result<T, E>
を Option<E>
に変換する
Ok
は潰れて None
になる
pub fn err(self) -> Option<E>
Example
let x: Result<u32, &str> = Ok(2);
assert_eq!(x.err(), None);
let x: Result<u32, &str> = Err("Nothing here");
assert_eq!(x.err(), Some("Nothing here"));
std::Option
また、 Rust には Option 型と言われるものがあり、これは値が存在するかどうかを表現するための列挙型です。
Some 値を持つ場合は Some(v) という値を、値が存在しない場合は None という値を持ちます。
Option 型は、Rust においてエラーハンドリングに使われるだけでなく、 Rust のパターンマッチングにおいても頻繁に使われます。
doc.rust-lang.org
pub enum Option<T> {
None,
Some(T),
}
map
Some
の場合には関数を適用してNone
の場合にはそのままにして Option
を返す
pub fn map<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> U,
Example
let maybe_some_string = Some(String::from("Hello, World!"));
let maybe_some_len = maybe_some_string.map(|s| s.len());
assert_eq!(maybe_some_len, Some(13));
map_or
Some
の場合には関数を適用してNone
の場合にはデフォルト値を返す
pub fn map_or<U, F>(self, default: U, f: F) -> U
where
F: FnOnce(T) -> U,
Example
let x = Some("foo");
assert_eq!(x.map_or(42, |v| v.len()), 3);
let x: Option<&str> = None;
assert_eq!(x.map_or(42, |v| v.len()), 42);
map_or_else
Some
の場合には関数を適用してNone
の場合には別のデフォルト関数を適用する
pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
where
D: FnOnce() -> U,
F: FnOnce(T) -> U,
Example
let k = 21;
let x = Some("foo");
assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
let x: Option<&str> = None;
assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
unwrap
Some
の場合には値をそのまま返して None
の場合にはパニックを起こす
pub fn unwrap(self) -> T
Example
let x = Some("air");
assert_eq!(x.unwrap(), "air");
let x: Option<&str> = None;
assert_eq!(x.unwrap(), "air");
unwrap_or
Some
の場合には値をそのまま返して None
の場合には引数の値をデフォルト値として返す
pub fn unwrap_or(self, default: T) -> T
Example
assert_eq!(Some("car").unwrap_or("bike"), "car");
assert_eq!(None.unwrap_or("bike"), "bike");
unwrap_or_else
Some
の場合には値をそのまま返して None
の場合には引数で受けたクロージャの返り値を返す
pub fn unwrap_or_else<F>(self, f: F) -> T
where
F: FnOnce() -> T,
Example
let k = 10;
assert_eq!(Some(4).unwrap_or_else(|| 2 * k), 4);
assert_eq!(None.unwrap_or_else(|| 2 * k), 20);
unwrap_or_default
Some
の場合には値をそのまま返して None
の場合には Some
の型のデフォルト値を返す
pub fn unwrap_or_default(self) -> T
where
T: Default,
Example
let good_year_from_input = "1909";
let bad_year_from_input = "190blarg";
let good_year = good_year_from_input.parse().ok().unwrap_or_default();
let bad_year = bad_year_from_input.parse().ok().unwrap_or_default();
assert_eq!(1909, good_year);
assert_eq!(0, bad_year);
and_then
Some
の場合には関数を呼び出して None
の場合には値をそのままにして Option
を返す
Some
型が返ってくるmap
と異なり、関数の返り値も Option
になっている
pub fn and_then<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> Option<U>,
Example1
fn sq_then_to_string(x: u32) -> Option<String> {
x.checked_mul(x).map(|sq| sq.to_string())
}
assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None);
assert_eq!(None.and_then(sq_then_to_string), None);
Example2: Err
を返すかもしれないメソッドチェーンの操作内で用いられる
let arr_2d = [["A0", "A1"], ["B0", "B1"]];
let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
assert_eq!(item_0_1, Some(&"A1"));
let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
assert_eq!(item_2_0, None);
or_else
Some
の場合には値をそのままにして None
の場合には関数を呼び出して Option
を返す
pub fn or_else<F>(self, f: F) -> Option<T>
where
F: FnOnce() -> Option<T>,
Example
fn nobody() -> Option<&'static str> { None }
fn vikings() -> Option<&'static str> { Some("vikings") }
assert_eq!(Some("barbarians").or_else(vikings), Some("barbarians"));
assert_eq!(None.or_else(vikings), Some("vikings"));
assert_eq!(None.or_else(nobody), None);
ok_or*
Some(v)
を Ok(v)
に、 None
を Err(err)
にマッピングして Option<T>
を Result<T, E>
に変換する
pub fn ok_or<E>(self, err: E) -> Result<T, E>
Example
let x = Some("foo");
assert_eq!(x.ok_or(0), Ok("foo"));
let x: Option<&str> = None;
assert_eq!(x.ok_or(0), Err(0));
ok_or_else*
Some(v)
を Ok(v)
に、 None
を Err(err())
にマッピングして Option<T>
を Result<T, E>
に変換する
pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
where
F: FnOnce() -> E,
Example
let x = Some("foo");
assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
let x: Option<&str> = None;
assert_eq!(x.ok_or_else(|| 0), Err(0));
Tips
Result
→ Option
は map_or_else
で None と Some を返すようにして変換できる
Option
→ Result
は ok_or
あるいは ok_or_else
で変換できる