S-JIS[2024-09-17/2024-10-07] 変更履歴

Rust Result列挙型

Ruststd::result::Resultのメモ。


概要

Result列挙型は、正常な値と異常な場合の値(エラー内容)のいずれかを保持する列挙型
Result列挙型はstd::preludeに含まれているので、useしなくても使える。


Resultインスタンスを作るには、正常な場合はOkを使い、エラーの場合はErrを使う。

    // 正常な場合
    let r: Result<i32, &str> = Ok(123);
    println!("{:?}", r);

    // エラーを返す場合
    let r: Result<i32, &str> = Err("エラー!");
    println!("{:?}", r);
    match r {
        Ok(n) => println!("ok = {}", n),
        Err(message) => println!("error = {}", message),
    }

クレート独自のResultを定義してそれを使うということもよく行われるようだ。[2024-10-07]
独自Resultを定義する例


Resultと ?演算子の関係

自分の関数(やメソッド)の戻り型がResultで、自分の関数内から呼び出している関数の戻り型もResultのとき、Errが返ってきたらそのErrをそのまま自分の呼び出し元に返したいことがある。

これを素直にコーディングすると以下のようになる。

fn func1() -> Result<i32, String> {
    let r = func2();
    let n = match r {
        Ok(n) => n,
        Err(e) => return Err(e),	// エラーのときはエラーを返す
    };
    Ok(n + 1)
}
fn func2() -> Result<i32, String> {
    Err(String::from("エラーの実験"))
}

?演算子を使うと、この処理を簡単に記述することが出来る。

fn func1() -> Result<i32, String> {
    let n = func2()?;
    Ok(n + 1)
}

?演算子は、Okのときはそれが保持している値を返し、ErrのときはErrをreturnする。
Errをreturnする(Errが関数の戻り値になる)ので、自分の関数の戻り型がResultでないと使えない。

ちなみに、?演算子は関数やメソッド呼び出しで使われることが多いが、変数に対しても使える。

    let r = func2();
    let n = r?;

Rustでは演算子をオーバーロードすることが出来る。(自分の構造体で加算「+」とか減算「-」とかを使うことが出来るようになる)
そのために、演算子とそれに対応するトレイトが決められており、そのトレイトを実装すれば対応する演算子が使えるようになる。
→演算子とトレイトの対応関係:core::ops

?演算子にはTryトレイトが対応しており、Result列挙型はTryトレイトを実装している。


Resultのメソッド

Result<T, E>のメソッド(抜粋)。[2024-10-06]

メソッド 説明
is_ok(&self) -> bool Okかどうか。 let ok: Result<i32, &str> = Ok(123);
let no: Result<i32, &str> = Err("error");
assert_eq!(true, ok.is_ok());
assert_eq!(false, no.is_ok());
is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool Okのときはfを実行してその結果を返す。
Errのときはfalseを返す。
let ok: Result<i32, &str> = Ok(123);
let o1: Result<i32, &str> = Ok(100);
let no: Result<i32, &str> = Err("error");
assert_eq!(true, ok.is_ok_and(|n| n > 100));
assert_eq!(false, o1.is_ok_and(|n| n > 100));
assert_eq!(false, no.is_ok_and(|n| n > 100));
is_err(&self) -> bool Errかどうか。 let ok: Result<i32, &str> = Ok(123);
let no: Result<i32, &str> = Err("error");
assert_eq!(false, ok.is_err());
assert_eq!(true, no.is_err());
is_err_and(self, f: impl FnOnce(E) -> bool) -> bool Errのときはfを実行してその結果を返す。
Okのときはfalseを返す。
let ok: Result<i32, &str> = Ok(123);
let no: Result<i32, &str> = Err("error");
let n2: Result<i32, &str> = Err("fatal");
assert_eq!(false, ok.is_err_and(|s| s == "fatal"));
assert_eq!(false, no.is_err_and(|s| s == "fatal"));
assert_eq!(true, n2.is_err_and(|s| s == "fatal"));
expect(self, msg: &str) -> T Okのときは値(と所有権)を返す。
Errのときはメッセージ付きのパニックを起こす。
let result: Result<i32, &str> = Ok(123);
let n = result.expect("error");
assert_eq!(123, n);
unwrap(self) -> T Okのときは値(と所有権)を返す。
Errのときはパニックを起こす。
?演算子
let result: Result<i32, &str> = Ok(123);
let n = result.unwrap();
assert_eq!(123, n);
unwrap_or(self, default: T) -> T Okのときは値(と所有権)を返す。
Errのときは引数defaultの値を返す。
let ok: Result<i32, &str> = Ok(123);
let no: Result<i32, &str> = Err("error");
assert_eq!(123, ok.unwrap_or(0));
assert_eq!(0, no.unwrap_or(0));
unwrap_or_default(self) -> T
T: Default
Okのときは値(と所有権)を返す。
ErrのときはTのデフォルト値を返す。
TがDefaultトレイトを実装しているとき(デフォルト値を返せるとき)だけ使用可能。
let ok: Result<i32, &str> = Ok(123);
let no: Result<i32, &str> = Err("error");
assert_eq!(123, ok.unwrap_or_default());
assert_eq!(0, no.unwrap_or_default());
unwrap_or_else<F: FnOnce(E) -> T>(self, op: F) -> T    
unwrap_unchecked(self) -> T    
unwrap_err_unchecked(self) -> E    
expect_err(self, msg: &str) -> E
T: fmt::Debug
Errのときはエラーの値(と所有権)を返す。
Okのときはメッセージ付きのパニックを起こす。
 
unwrap_err(self) -> E
T: fmt::Debug
Errのときはエラーの値(と所有権)を返す。
Okのときはパニックを起こす。
 
as_ref(&self) -> Result<&T, &E>    
as_mut(&mut self) -> Result<&mut T, &mut E>    
map<U, F>(self, op: F) -> Result<U, E>
F: FnOnce(T) -> U
Result<T, E>をResult<U, E>に変換する。
(Okの型をTからUに変換する)
let r1: Result<i32, &str> = Ok(123);
let r2 = r1.map(|n| format!("n={}", n));
map_or<U, F>(self, default: U, f: F) -> U
F: FnOnce(T) -> U
   
map_or_else<U, D, F>(self, default: D, f: F) -> U
D: FnOnce(E) -> U
F: FnOnce(T) -> U
   
map_err<F, O>(self, op: O) -> Result<T, F>
O: FnOnce(E) -> F
Result<T, E>をResult<T, F>に変換する。
(Errの型をEからFに変換する)
let r1: Result<i32, &str> = Err("error");
let r2 = r1.map_err(|_s| -1);
inspect<F: FnOnce(&T)>(self, f: F) -> Self    
inspect_err<F: FnOnce(&E)>(self, f: F) -> Self    
ok(self) -> Option<T> Result<T, E>をOption<T>に変換する。
OkはSome、ErrはNoneになる。
let ok: Result<i32, &str> = Ok(123);
let no: Result<i32, &str> = Err("error");
assert_eq!(Some(123), ok.ok());
assert_eq!(None, no.ok());
err(self) -> Option<E> Result<T, E>をOption<E>に変換する。
OkはNone、ErrはSomeになる。
let ok: Result<i32, &str> = Ok(123);
let no: Result<i32, &str> = Err("error");
assert_eq!(None, ok.err());
assert_eq!(Some("error"), no.err());
as_deref(&self) -> Result<&T::Target, &E>
T: Deref
   
as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E>
T: DerefMut
   
iter(&self) -> Iter<'_, T>    
iter_mut(&mut self) -> IterMut<'_, T>    
into_ok(self) -> T
E: Into<!>
   
into_err(self) -> E
T: Into<!>,
   
and<U>(self, res: Result<U, E>) -> Result<U, E>    
and_then<U, F>(self, op: F) -> Result<U, E>
F: FnOnce(T) -> Result<U, E>
   
or<F>(self, res: Result<T, F>) -> Result<T, F>    
or_else<F, O>(self, op: O) -> Result<T, F>
O: FnOnce(E) -> Result<T, F>
   

stdへ戻る / Rustへ戻る / 技術メモへ戻る
メールの送信先:ひしだま