Tak's Notebook

Kaggle, Machine Learning, Engineering

Rust の Result と Option のメソッドまとめ

項目の末尾の * は 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);

// This example panics
let x: Result<u32, &str> = Err("emergency failure");
x.unwrap(); // panics with `emergency failure`

unwrap_err*

  • Ok の場合にはパニックを起こして Err の場合には値をそのまま返す
pub fn unwrap_err(self) -> E
where
    T: Debug,

Example

// This example panics
let x: Result<u32, &str> = Ok(2);
x.unwrap_err(); // panics with `2`

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};

// Note: on Windows "/" maps to "C:\"
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

/*
   Converts an Option<String> into an Option<usize>, consuming the original:
*/
let maybe_some_string = Some(String::from("Hello, World!"));
// `Option::map` takes self *by value*, consuming `maybe_some_string`
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");

// This example panics
let x: Option<&str> = None;
assert_eq!(x.unwrap(), "air"); // fails

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); // overflowed!
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) に、 NoneErr(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) に、 NoneErr(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

  • ResultOptionmap_or_else で None と Some を返すようにして変換できる
  • OptionResultok_or あるいは ok_or_else で変換できる