Rust 基礎からマスターまで — 第4回
構造体と列挙で有効な状態を表現する
本ブログ作成文は、講義を目指して製作されました。 また、作成された文章の情報も間違っている可能性がありますので、ご注意ください。
構造体は関連データを束ね、enumは可能な状態をリストします。 両方を一緒に使用すれば、存在できない組み合わせをフィールドとブールで無理やり表現する必要はありません。
構造体とimpl
struct Player {
name: String,
health: i32,
}
impl Player {
fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
health: 100,
}
}
fn take_damage(&mut self, amount: i32) {
self.health = (self.health - amount.max(0)).max(0);
}
}
implブロックは、構造体に関連する生成関数とメソッドを定義します。 &mut selfは、メソッドがオブジェクトを変更するために排他的に借りることを意味します。
enumで状態を表現する
enum QuestState {
Locked,
Active { progress: u32, goal: u32 },
Completed { reward_claimed: bool },
}
Activeの時だけ progress があり、 Completed の時だけ報酬の受け取り状態がある。 複数のboolフィールドとnullableフィールドで同じ情報を表現する場合よりも、間違った組み合わせが減ります。
パターンマッチング
fn describe(state: &QuestState) -> String {
match state {
QuestState::Locked => String::from("Locked"),
QuestState::Active { progress, goal } => {
format!("{progress}/{goal}")
}
QuestState::Completed { reward_claimed: true } => {
String::from("Reward claimed")
}
QuestState::Completed { reward_claimed: false } => {
String::from("Reward ready")
}
}
}
matchはenumのすべてのケースを処理したかどうかをチェックします。 新しい状態を追加すると、処理されていないコードがコンパイルエラーになります。
OptionとResultも同じenumです。 Rustでは状態と失敗の可能性を型で表現し、matchや専用メソッドで各ケースを処理する。