項目3:OptionとResultに対してはmatchを用いずに変換しよう
LT;DR
Option と Result に対して、明示的な match を行うよりも、変換を使おう
具体的には、? 演算子が適用できるような型に変換しよう
変換に参照が絡む場合は as_ref メソッドを使おう
Option よりも Result を使おう
hr.icon
None や Err を無視したい場合、if let を用いるのが良い
code:rs
if let Some(i) = &s.field {
println!("field is {i}")
}
None や Err 時は パニック を起こしたい場合、unwrap や expect メソッドを用いるのが良い expect は失敗時のエラーメッセージを指定することが可能
code:rs
let f = std::fs::File::open("/etc/passwd").unwrap();
warning.icon
エラー処理 は、別の人に判断を委ねることが正しい判断であることが多い 特にライブラリの場合、コードは作成者が予測できないような様々な環境で使用される
利用者の負担を軽減するためにも、「Result と Option を用いよう」
エラーを伝搬する場合、? を用いるのが良い
?: シュガーシンタックス で、Err へマッチし、必要に応じてエラー型を変換して return Err(...) を生成する code:rs
pub fn find_user(username: &str) -> Result<UserId, std::io::Error> {
let f = std::fs::File::open("/etc/passwd")?;
// ...
}
? が呼び出すメソッドは #[inline] (インライン関数)としてマークされているため、手動で書いたコードと全く同じになる 複数のエラーを手動でマッピングする場合、map_err メソッドを用いるのが良い
code:rs
pub fn find_user(username: &str) -> Result<UserId, String> {
let f = std::io::File::open("/etc/passwd")
.map_err(|e| format!("Failed to open password file: {:?}", e))?;
// ...
}
warning.icon From トレイトを用いると、map_err を呼び出さずとも、コンパイラが自動的に変換できる
この種の変換は一般化することができ、標準ライブラリで様々な変換メソッドが用意されている
https://effective-rust.com/images/transform.svg
* が付いているのは、panic! する可能性がある
上記以外でよく用いられるメソッドとして、参照を別の型の参照に変換する as_ref メソッドがある
code:rs
pub fn encrypt(payload: &u8) -> Vec<u8> { // ...
}
struct InputData { payload: Option<Vec<u8>> }
impl InputData {
pub fn enctypted(&self) -> Vec<u8> {
encrypt(self.payload.as_ref().unwrap.or(&vec![]))
}
}
Result vs Option
下記の 2 つの理由から、Result を用いたほうが良い
1. エラー発生時、Result では Err に有益な情報を含めることができる
2. Result には #[must_use] アトリビュートが付いているので、コードが返された Result を無視した場合に、コンパイラに警告を表示させることが可能