0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(DAY19) 俺と学ぶRust言語~Result~

Posted at

今日の内容

  • Result

はじめに

前回はOptionについて学びました。
今回は、Result について学びます。

Resultとは

Result<T, E>は、Rustにおけるエラーハンドリングのための列挙型です。処理の結果が「Ok」か「Err」かを表現します。

  • Ok(T): 成功した場合に返す値を格納する
  • Err(E): 失敗した場合に返すエラーを格納する

これにより、Rustは例外(try-catch)の代わりに、コンパイル時にエラーを明確に扱うことができます。

Resultの定義

Result型は次のように定義されています。
標準ライブラリに用意されています。

enum Result<T, E> {
    Ok(T),
    Err(E),
}
  • T: 成功時の値の型
  • E: エラー時の情報の型

Resultの基本的な使い方

1.基本例

次の例では、整数の割り算を行い、ゼロ除算が発生した場合にエラーメッセージを返す関数を定義しています。

fn divide(a:i32, b:i32) -> Result<i32, String> {
    if b == 0 {
        Err("cannot divide by zero!".to_string())
    } else {
        Ok(a / b)
    }
}

fn main() {
    match divide(10, 2) {
        Ok(result) => println!("{} / {} = {}", 10, 2, result),
        Err(e) => println!("{}", e),
    }
    match divide(10, 0) {
        Ok(result) => println!("{} / {} = {}", 10, 0, result),
        Err(e) => println!("{}", e),
    }
}
/******** 実行結果 ********
10 / 2 = 5
cannot divide by zero!
*************************/

2.Resultの値を取り出す方法

  1. match構文で取り出す
    Optionと同様、match構文を使って値を取り出せます
    fn main() {
    let result: Result<i32, &str> = Ok(42);
    match result {
            Ok(value) => println!("成功: {}", value),
            Err(err) => println!("エラー: {}", err),
        }
    }
    /******** 実行結果 ********
    成功: 42
    *************************/
    
  2. unwrap
    unwrapはErrの場合にプログラムをクラッシュさせます
    安全性を損なうため、基本的には避けるべきです
    fn main() {
        let result: Result<i32, &str> = Ok(42);
        println!("{}", result.unwrap());
    }
    /******** 実行結果 ********
    42
    *************************/
    
  3. unwrap_or
    Errの場合に指定したデフォルト値を返します
    fn main() {
        let result: Result<i32, &str> = Err("エラー");
        println!("{}", result.unwrap_or(0));
    }
    /******** 実行結果 ********
    0
    *************************/
    
  4. unwrap_or_else
    クロージャを使ってデフォルト値を計算できます
    fn main() {
        let result: Result<i32, &str> = Err("エラー");
        let value = result.unwrap_or_else(|e| {
            println!("エラー内容: {}", e);  
            -1  // デフォルト値
        });
        println!("{}", value);
    }
    /******** 実行結果 ********
    エラー内容: エラー
    -1
    *************************/
    

よく使う便利なメソッド

  1. is_okとis_err
    ResultがOkかErrかを判定します
    let success: Result<i32, &str> = Ok(42);
    let failure: Result<i32, &str> = Err("エラー");
    
    println!("{}", success.is_ok());//true
    println!("{}", failure.is_err());//true
    
  2. map
    Okの値を変換します
    let result: Result<i32, &str> = Ok(10);
    let doubled = result.map(|x| x * 2);
    println!("{:?}", doubled);//Ok(20)
    
  3. and_then
    Okの場合にさらに別のResultを返す処理を行います
    fn to_even(x: i32) -> Result<i32, &'static str>{
        if x % 2 == 0 {
            Ok(x)
        } else {
            Err("奇数です")
        }
    }
    fn main() {
        let result = Ok(4).and_then(to_even);
        println!("{:?}", result);
        let result = Ok(3).and_then(to_even);
        println!("{:?}", result);
    }
    /******** 実行結果 ********
    Ok(4)
    Err("奇数です")
    *************************/
    
  4. or_else
    Errの場合に別の処理を実行します
    fn main() {
        let result:Result<i32, &str> = Err("エラー");
        let recovered: Result<i32, &str> = result.or_else(|e| {
            println!("復帰処理: {}", e);
            Ok(0)
        });
        println!("{:?}", recovered);
    }
    /******** 実行結果 ********
    復帰処理: エラー
    Ok(0)
    *************************/
    
  5. ?
    Resultを扱う際の簡略記法
    Okなら値を返し、Errなら関数を早期終了します
    fn read_file(file_path: &str) -> Result<String, std::io::Error> {
        let content = std::fs::read_to_string(file_path)?;
        Ok(content)
    }
    fn main() {
        let content = read_file("test.txt");
        println!("{}", content.unwrap());
    }
    

OptionとResultの違い

前回学んだOptionとResultは似ていますが、異なる機能です。以下の表に示しました。

特徴 Option Result
目的 値が「存在するか」「しないか」を表現 成功かエラーかを表現
列挙子 Some/None Ok/Err
主な用途 任意の値 エラーハンドリング

おわりに

今回はResultについて学びました。
次回は、OptionとResultを組み合わせたエラーハンドリングの応用について学んでいきます。
ご精読、ありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?