データを持つ Enum
CoddyのRustジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 14/61。
Rustの基本的なenumでは、Direction::NorthやStatus::Activeのように、バリアントの集合が固定された型を定義できます。しかし、Rustのenumはそれよりはるかに強力です。各バリアントは独自のデータを持つことができるため、enumは現実世界のシナリオをモデル化するうえで非常に柔軟です。
異なるメッセージ型がそれぞれ異なる情報を持つメッセージングシステムを考えてみましょう。テキストメッセージには内容があり、移動コマンドには座標があり、終了シグナルには何もありません。Rustでは、これらすべてを単一のenumで表現できます。
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
Each バリアントは異なる形を持ちます。Quit はデータを holds しません。単なるシグナルです。
Moveはnamedフィールドを持つ構造体風の構文を使用します。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であることです。同じコレクションに格納したり、同じ関数に渡したり、1つの関数から任意のバリアントを返したりできます。enumは、各バリアントに必要な固有の情報を保持しながら、異なるデータ形状を1つの型の下に統合します。
チャレンジ
簡単data を含む enum を使用して、さまざまな種類の alert を表す notification システムを構築しましょう。それぞれの notification type は異なる情報を持ちます。message を持つもの、数値を持つもの、単純な signal であるものがあります。
コードを整理するために、2つのファイルを作成します。
notification.rs: 3つの variant を持つ public なNotificationenum を Define します。Alert: 1つのStringmessage を保持します(tuple syntax)Reminder: named fields を保持します:title(String)とminutes(u32)Dismiss: data を持たず、単なる signal です
main.rs: notification module を取り込み、各 variant の instance を1つずつ作成します。次に、3つの variant が同じ type でありながら異なる data を持てることを示すため、それぞれの notification に関する情報を Print します。
Print する際は、各 notification を表示するために debug formatting({:?})を使用します。この方法で Print できるように、enum に Debug trait を derive する必要があります。
出力には、3つすべての notification がそれぞれ1行ずつ表示されます。
Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
Dismissたとえば、alert message が "Server down"、reminder の title が "Meeting"、minutes が 30 の場合、出力は次のようになります。
Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
Dismiss入力として、alert message、reminder title、reminder minutes の3つを受け取ります。
REQUIRED OUTPUT FORMAT:自分で試してみよう
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: Create a Reminder notification using reminder_title and reminder_minutes
// TODO: Dismiss 通知を作成する
// TODO: デバッグフォーマット {:?} を使用して各通知を出力する
// 各通知はそれぞれ独自の行に出力すること
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rustオンラインコンパイラ