🔲

RustのResult型とOption型のエラーチェックがコードレビュー後にスッキリした話

に公開

初期実装(unwrapで例外を処理していないので非推奨)

let cookie_data: Option<&MetadataValue<Ascii>> = request.metadata().get("cookie");

if cookie_data.is_none() {
    return Err("cookieがありません");
}

let cookie: &str = cookie_data.unwrap().to_str().unwrap();
println!("{}", cookie);

unwrap無しにした版

let cookie_data: Option<&MetadataValue<Ascii>> = request.metadata().get("cookie");

let cookie: &str = match cookie_data {
    Some(cookie) => cookie.to_str().map_err(|_| {
        Err("cookieが不正です")
    })?,
    None => {
        return Err("cookieがありません")
    }
};
println!("{}", cookie);

最終版

let cookie_data = request.metadata().get("cookie");

// cookie情報を取得する
let cookie: &str = cookie_data // Option<&MetadataValue<Ascii>>
    .ok_or_else(|| Err("cookieがありません"))?
    .to_str() // Result<&str, ToStrError>
    .map_err(|_| Err("cookieが不正です"))?;
println!("{}", cookie);

Option型の場合は、.ok_or_else
Result型の場合は、.map_err

を使っている。

Result型とOption型で、ハンドリング方法は揃えてくれたらいいのにと思った。

余談

fn main() {
    let value: Option<usize> = Some(1);

    let result = value.ok_or({ println!("出力される"); 0 }); // output 出力される
    println!("{}", result.unwrap()); // output 1

    let result = value.ok_or_else(|| { println!("出力されない"); 0 });
    println!("{}", result.unwrap()); // output 1
}

ok_orok_or_else は、基本同じ動作となるが ok_or のほうは直感に反する動きをするので、ok_or_else 推奨となる。

所感

最終版はスッキリとしたなと。

Discussion