Rust 基礎からマスターまで — 第7回
Resultとモジュール、Cargoでエラーとプロジェクトを管理する
本ブログ作成文は、講義を目指して製作されました。 また、作成された文章の情報も間違っている可能性がありますので、ご注意ください。
Rustは回復可能な失敗をResultとして表現します。 プロジェクトが大きくなると、エラータイプとともにモジュール境界、Cargo設定、テストもコード契約の一部となる。
Result と疑問符演算子
use std::fs;
use std::io;
fn load_config(path: &str) -> Result<String, io::Error> {
let text = fs::read_to_string(path)?;
Ok(text)
}
? は、成功値の場合は内側の値を取り出し、失敗した場合は現在の関数からエラーを返します。 エラーを無視する文法ではなく、呼び出し元に渡す短い表現です。
エラーにコンテキストを追加する
fn parse_level(text: &str) -> Result<u32, String> {
text.trim()
.parse::<u32>()
.map_err(|error| format!("invalid level: {error}"))
}
ライブラリは呼び出し側が処理できるようにエラーを返し、プログラムの境界でログまたはユーザーメッセージに置き換えることができます。 予想される入力エラーにpanicを使用すると、回復の機会が失われます。
モジュールで公開範囲を設定する
mod combat {
pub struct Damage(pub u32);
pub fn calculate(attack: u32, defense: u32) -> Damage {
Damage(attack.saturating_sub(defense).max(1))
}
}
基本項目はモジュールしか公開されず、pubを付けた契約のみ使用できる。 内部実装を隠すことで、変更が他のモジュールに広がる範囲を減らすことができます。
Cargoとテスト
#[cfg(test)]
mod tests {
use super::combat;
#[test]
fn damage_is_at_least_one() {
assert_eq!(combat::calculate(5, 100).0, 1);
}
}
Cargoは、依存関係、ビルド、テスト、文書生成を1つのプロジェクトルールで管理します。 エラータイプとモジュール公開範囲を小さく保つと、使用する方が知るべき契約も小さくなる。