データを持つ Enum
CoddyのRustジャーニー「Object Oriented Programming」セクションの一部 — レッスン 14/61。
Rustの基本的な列挙型(enum)を使用すると、Direction::North や Status::Active のように、固定されたバリアントのセットを持つ型を定義できます。しかし、Rustの列挙型はそれよりもはるかに強力です。各バリアントは独自のデータを保持できるため、列挙型は現実世界のシナリオをモデリングするのに非常に柔軟です。
異なるメッセージタイプが異なる情報を運ぶメッセージングシステムを考えてみましょう。テキストメッセージには内容があり、移動コマンドには座標があり、終了シグナルには何も含まれません。Rustでは、これらすべてを単一のenumで表現できます:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
各バリアントはそれぞれ異なる形をしています。Quitはデータを保持しません。単なるシグナルです。
Moveは名前付きフィールドを持つ構造体のような構文を使用します。Writeはタプル構文を使用して単一のStringを保持します。ChangeColorはRGBコンポーネントを表す3つの値を保持します。
これらのバリアントのインスタンスの作成は、次のようになります。
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);
このアプローチの素晴らしい点は、m1、m2、m3、およびm4がすべて同じ型であるということです:Message。これらを同じコレクションに格納したり、同じ関数に渡したり、単一の関数から任意のバリアントを返したりすることができます。列挙型(enum)は、各バリアントが必要とする特定の情報を保持しながら、異なるデータの形状を一つの型の下に統合します。
チャレンジ
簡単データを持つ列挙型(enum)を使用して、さまざまな種類のアラートを表現する通知システムを構築しましょう。各通知タイプは異なる情報を保持します。メッセージを持つもの、数値を持つもの、そして単純なシグナルであるものがあります。
コードを整理するために、2つのファイルを作成します:
notification.rs: 以下の3つのバリアントを持つパブリックなNotification列挙型を定義します:Alert— 1つのStringメッセージを保持します(タプル構文)Reminder— 名前付きフィールドtitle(String) とminutes(u32) を保持しますDismiss— データを保持せず、単なるシグナルです
main.rs: 通知モジュールを取り込み、各バリアントのインスタンスを1つずつ作成します。次に、各通知に関する情報を出力して、3つのバリアントがすべて同じ型でありながら異なるデータを保持していることを示します。
出力する際は、デバッグフォーマット ({:?}) を使用して各通知を表示してください。列挙型をこの方法で出力できるようにするには、Debug トレイトを継承(derive)する必要があります。
出力は、3つの通知すべてをそれぞれ個別の行に表示する必要があります:
Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
Dismiss例えば、アラートメッセージが "Server down"、リマインダーのタイトルが "Meeting" で 30 分の場合、出力は以下のようになります:
Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
Dismissアラートメッセージ、リマインダーのタイトル、リマインダーの分の3つの入力を受け取ります。
自分で試してみよう
mod notification;
use notification::Notification;
fn main() {
// 入力を読み込む
let mut alert_message = String::new();
std::io::stdin().read_line(&mut alert_message).expect("Failed to read line");
let alert_message = alert_message.trim().to_string();
let mut reminder_title = String::new();
std::io::stdin().read_line(&mut reminder_title).expect("Failed to read line");
let reminder_title = reminder_title.trim().to_string();
let mut minutes_input = String::new();
std::io::stdin().read_line(&mut minutes_input).expect("Failed to read line");
let reminder_minutes: u32 = minutes_input.trim().parse().expect("Failed to parse minutes");
// TODO: alert_message を使用して Alert 通知を作成する
// TODO: reminder_title と reminder_minutes を使用して Reminder 通知を作成する
// TODO: Dismiss 通知を作成する
// TODO: デバッグフォーマット {:?} を使用して各通知を表示する
// 各通知はそれぞれの行に表示される必要がある
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。