43518


[Rustの“unwrap()”は何をするものですか？](https://ja.stackoverflow.com/questions/1730/rust%E3%81%AEunwrap%E3%81%AF%E4%BD%95%E3%82%92%E3%81%99%E3%82%8B%E3%82%82%E3%81%AE%E3%81%A7%E3%81%99%E3%81%8B)を読んでいて、また、自身の短い経験を通して疑問をいただいたことがあるので質問です。  
`unwrap()`を使うシーンはいくつかあったのですが、なぜそもそも`Result<T>`のように`unwrap()`しないと値を取り出せない形になっているのでしょうか。そのまま`T`で値を返してくれたほうが毎回`unwrap()`しなくて便利だと思いますがどういった理由が考えられますでしょうか。


CC BY-SA 3.0
2018-04-24T06:56:59.540
43514
2018-04-24T14:18:21.433
28291
question
rust
なぜ`Result<T>`で値が返ってくるのか


関数の中には処理に失敗する可能性があるものもあります。たとえば、文字列を数字に変換する関数は入力の文字列が `"1"` なら整数の `1`
に変換できますが、 `"abc"`
では変換できません。また、ファイルを開いたり、ファイルから読み込んだり、書き込んだりする関数も処理に失敗する可能性があります（ファイルが存在しない、ディスクの空きスペースがなくなったなど）

処理が失敗した時には何らかの形で呼び出し元にそのことを伝えないといけません。そうすることで呼び出し元では適切なエラーメッセージを表示したり、なんらかの復旧処理（たとえばファイルが存在しないなら新たに作るなど）を行なったりできます。いくつかの言語では、処理の失敗を「例外」（exception）で表現しますが、Rust
では「値」で表現します。

`Result<T, E>` 型はそのような、処理が失敗するかもしれないことを表す値のひとつです。そして `Result<T, E>` の
`unwrap()` は値が `Ok<T>` の時は `T` を返し、`Err<E>` の時は panic を起こしてスレッドを強制終了します。

実用的なプログラムを開発する際、開発の初期では `unwrap()` を多用しますが、最終的には、処理の失敗を適切に処理するため、ほとんど全ての
`unwrap()` を `match` 式やコンビネータメソッドによる処理や、`?` 演算子によるエラーの伝搬に置き換えます。

たとえばこのプログラムは `unwrap()` が二つあり、ユーザーの入力に問題があると panic する可能性があります。

[code]

    use std::env;
    
    fn double_arg(mut argv: env::Args) -> i32 {
        let arg1 = argv.nth(1).unwrap();
        let n = arg1.parse::<i32>().unwrap(); 
        2 * n
    }
    
    fn main() {
        let n = double_arg(env::args());
        println!("{}", n);
    }
    
[/code]

これを以下のような感じに書き換えると、ユーザーの入力に問題があったら適切なエラーメッセージを表示して終了するようになります。

[code]

    use std::env;
    
    fn double_arg(mut argv: env::Args) -> Result<i32, CliError> {
        let arg1 = argv.nth(1).ok_or(CliError::NotEnoughArgs)?;
        let n = arg1.parse::<i32>()?;
        Ok(2 * n)
    }
    
    // いろいろと省略
    // ...
    
    fn main() {
        match double_arg(env::args()) {
            Ok(n) => println!("{}", n),
            Err(err @ CliError::NotEnoughArgs) => println!("エラー：{}", err),
            Err(CliError::Parse(..)) => {
                println!("エラー：不正な数字です \"{}\"",
                         env::args().nth(1).unwrap())
            }
        }
    }
    
[/code]

手前味噌ですが、Rust におけるエラー処理の基本をこちらの記事で詳しく説明していますので、お時間のある時にぜひ読んでみてください。

  * [RustでOption値やResult値を上手に扱う](https://qiita.com/tatsuya6502/items/cd41599291e2e5f38a4a)


CC BY-SA 3.0
2018-04-24T07:38:12.043
43517
2018-04-24T07:38:12.043
14101
43514
answer


こんにちは。`unwrap` や `Result` の話はドキュメントの[エラーハンドリング](https://rust-lang-
ja.github.io/the-rust-programming-language-ja/1.6/book/error-
handling.html)に詳しく書かれているのですが、質問から察するにRustのコードとりあえず書いてみて、生じた疑問を書いている状況でしょうか。そういう想定の下、回答します。

ひとまず、質問に対する直接的な回答は「`unwrap`で取り出す値以外の可能性もあるから」です。以下にこれを丁寧に説明します。

まず、
Rustは例外を使わず返り値で失敗を表します。他言語でいう例外に綺麗に対応するものはありません。しかし失敗する可能性のある計算というのもあります。たとえば文字列を数値にパースするだとかの処理ですね。  
そういう成功するか失敗するか分からない計算の返り値に `Result` が使われます。  
参考のリンクに貼られている回答では`Result<T>`と書いていますがあれは恐らく省略したかtypoで、本来は `Result<T, E>`
です。`T`が成功した場合の値、`E`が失敗した場合の値です。

たとえば`Result` を返す [`parse`](https://doc.rust-
lang.org/beta/std/primitive.str.html#method.parse)は以下のように成功した場合と失敗した場合の処理を記述できます。

[code]

    fn main() {
        match "not a number".parse::<i32>() {
            Ok(n) => println!("got a number {}", n),
            Err(e) => println!("failed to parse: {}", e),
        }
        // -> failed to parse: invalid digit found in string
    }
    
[/code]

なので

> なぜそもそもResultのようにunwrap()しないと値を取り出せない形になっているのでしょうか。

の質問はやや正しくなく、`unwrap` は取り出す手段の一つですね。  
`unwrap` はこのエラー処理をせず、エラーが起きたらそのままRustのプログラムを終了させてしまう(panicする)関数です(試しに `"not a
number".parse::<i32>().unwrap()` などと呼んでみると分かるかと思います)。  
有無を言わさずプログラムを終了して開発者向けのメッセージだけ残すのであまり行儀のいいものではないのですがエラー処理を省けるのでチュートリアルなどでよく使われます。

まとめると

  * `Result` を返しているのは失敗する可能性もあるから
  * 「`unwrap` で値を取り出す」は実はあまり良くない書き方


CC BY-SA 3.0
2018-04-24T07:47:13.143
43518
2018-04-24T07:47:13.143
22816
43514
answer


Rustのことはあまり詳しくありませんが、質問者が知りたいのは型システムの設計思想に関する話題と見受けられます。下記のURLにhaskellの例ですが、なぜ値をラッピングするのか。ということについて書かれています。一度じっくり読まれてはいかがでしょうか。  
<https://www.infoq.com/jp/articles/Understanding-Monads-guide-for-perplexed>  
僕が思うのは記述が短かったりプログラムがエラーで落ちることを許容するならばラッピングは煩雑だと思いますが、複雑なデータフローをプログラミングするときにこうしたラッピング（例外やOption型）がないとデバッグするのがものすごく大変になります。どこでデータフローがおかしくなっているのかが簡単にわからないですからね。


CC BY-SA 3.0
2018-04-24T14:18:21.433
43529
2018-04-24T14:18:21.433
25980
43514
answer