53068


下記の様なコードがあった場合、エラーケースではsplitでエラーが発生します。  
mapなどを繋げて書いた際の途中でエラーが発生する場合、  
Rustでうまくエラーハンドリングするにはどの様に書くのが良いですか

[code]

    use std::collections::HashMap;
    
    fn to_hash(kv: &str) -> Result< HashMap<String,String>, String> {
        let _hashmap  = kv
            .split(',')
            .map(|kv| kv.split('='))
            .map(|mut kv| (kv.next().unwrap().into(), kv.next().unwrap().into()))
            .collect::<HashMap<String, String>>();
        Ok(_hashmap)
    
        // Err handling?
    }
    fn main() {
        // Ok.
        let kv1 = "key1=value1,key2=value2,key3=value3";
        match to_hash(kv1) {
            Ok(n) =>  println!("{:?}",n),
            Err(e) => println!("{:?}",e),
        }
    
        // Err.
        let kv2 = "key1=value1,key2=value2,key3=value3,";
        match to_hash(kv2) {
            Ok(n) =>  println!("{:?}",n),
            Err(e) => println!("{:?}",e),
        }
    
    }
    
[/code]


CC BY-SA 4.0
2019-02-27T08:50:03.553
53066
2019-02-27T09:43:44.253
32285
question
rust
Rustのmapなどで繋げて記載した場合のエラーハンドリングについて


こんにちは、κeenです。  
エラーが出て困っているわけではなくてエラーを適切に処理する方法を知りたいということでよろしいですか？  
Rustでは回復不可能なパニックと、値として取り扱えるエラーは区別されています。今回はパニックが出て困っているのでエラーにしたいという質問として受け取りました。

以下のように書き換えるのはどうでしょう。

[code]

    // * .unwrap() を使うとパニックになってしまい、そのままプログラムが終了してしまうので極力使わない。
    // * ResultやOptionはそのまま伝播させて使う。
    
    use std::collections::HashMap;
    
    fn to_hash(kv: &str) -> Result<HashMap<String, String>, String> {
        kv.split(',')
            .map(|kv| kv.split('='))
            // 説明のわかりやすさのために型を明示する。なくてもコンパイルは通る
            .map(|mut kv| -> Option<(String, String)> {
                // `?` 演算子で `None` だった場合にそのまま関数(クロージャ)から返せる。
                Some((kv.next()?.into(), kv.next()?.into()))
            })
            // collectは Option<T>, Option<T>, ... のイテレータから Option<Tのコレクション> を作れる。
            .collect::<Option<HashMap<String, String>>>()
            // Option -> Resultの変換関数として `ok_or`, `ok_or_else` が用意されている
            .ok_or_else(|| "error occurred".into())
        // Err handling?
    }
    fn main() {
        // Ok.
        let kv1 = "key1=value1,key2=value2,key3=value3";
        match to_hash(kv1) {
            Ok(n) => println!("{:?}", n),
            Err(e) => println!("{:?}", e),
        }
    
        // Err.
        let kv2 = "key1=value1,key2=value2,key3=value3,";
        match to_hash(kv2) {
            Ok(n) => println!("{:?}", n),
            Err(e) => println!("{:?}", e),
        }
    }
    
    
[/code]

ブラウザで試すには以下  
[https://play.rust-
lang.org/?version=stable&mode=debug&edition=2018&gist=65b15377022eec393433a17ba896a720](https://play.rust-
lang.org/?version=stable&mode=debug&edition=2018&gist=65b15377022eec393433a17ba896a720)

コメントにも書いていますが

  * unwrapを使わない
  * OptionやResultは出来る限り伝播させる

をするとエラーハンドリングできるようになります。

大分旧くなってしまいましたが旧版の公式ドキュメントでこのあたりが丁寧に解説されています。  
<https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/error-
handling.html>  
今は `try!` マクロは非推奨で [`?` が導入されました](https://rust-lang-nursery.github.io/edition-
guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-
easier-error-handling.html)がそれ以外は今でも使えるようです。


CC BY-SA 4.0
2019-02-27T09:43:44.253
53068
2019-02-27T09:43:44.253
22816
53066
answer