エラー時に消費した引数を返す
説明
失敗する可能性のある関数が引数を消費(move)した場合、その引数をエラーの中に返却しましょう。
例
pub fn send(value: String) -> Result<(), SendError> { println!("using {value} in a meaningful way"); // 非決定的な失敗し得るアクションをシミュレート。 use std::time::SystemTime; let period = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap(); if period.subsec_nanos() % 2 == 1 { Ok(()) } else { Err(SendError(value)) } } pub struct SendError(String); fn main() { let mut value = "imagine this is very long string".to_string(); let success = 's: { // value を2回送信してみる。 for _ in 0..2 { value = match send(value) { Ok(()) => break 's true, Err(SendError(value)) => value, } } false }; println!("success: {success}"); }
動機形成
エラーが発生した際、なにか別の手段を試したり、非決定的な関数であるならリトライしたくなるものです。しかし、もし引数が常に消費されてしまうのであれば、呼び出しのたびに引数をクローンしなければならなくなります。これではとても効率的とは言えません。
標準ライブラリでは、このアプローチを String::from_utf8
メソッドなどで使用しています。有効な UTF-8 を含まないベクタが与えられた場合、 FromUtf8Error
を返します。 FromUtf8Error::into_bytes
メソッドを使用することで、元のベクタを取得できます。
長所
可能な限り引数をmoveすることで、パフォーマンスを向上させます。
短所
エラーの型がやや複雑になります。