データバリアントのマッチング
CoddyのRustジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 16/61。
前のレッスンでは、異なるバリアントを処理するために enum のメソッド内で match を使用しました。ここでは、match がそれらのバリアント内に格納されたデータを実際にどのように取り出すのかに焦点を当てます。これは destructuring と呼ばれるテクニックです。
データを holds する enum バリアントに match すると、そのデータをパターン内で直接変数にバインドできます。
enum Event {
Click { x: i32, y: i32 },
KeyPress(char),
Resize(u32, u32),
}
fn handle_event(event: Event) {
match event {
Event::Click { x, y } => {
println!("Clicked at ({}, {})", x, y);
}
Event::KeyPress(key) => {
println!("Key pressed: {}", key);
}
Event::Resize(width, height) => {
println!("Resized to {}x{}", width, height);
}
}
}
各アームは、バリアントの構造に基づいて異なる方法でデータを抽出します。構造体のようなバリアントでは、{ field_name }を使って名前付きフィールドを取り出します。タプルバリアントでは、(width, height)のような位置変数を使います。
選択した変数名は、その match アーム内で使用できるようになります。これは、どのバリアントを持っているかを同時に確認し、さらにそのペイロードにアクセスできるため強力です。
コンパイラによってすべてのバリアントを handle でき、抽出された値はすぐに使用できます。追加の手順は必要ありません。
チャレンジ
簡単さまざまな種類のユーザーコマンドを処理するコマンドプロセッサを構築しましょう。各コマンドは異なるデータを持ち、プロセッサはパターンマッチングを使用してそのデータを抽出し、適切な応答を生成します。
コードを整理するために、2つのファイルを作成します。
command.rs:3つのバリアントを持つ publicCommandenum を定義します。Say:単一のStringメッセージを保持します(タプル構文)Move:named フィールドを保持します:direction(String)とsteps(u32)Calculate:加算する数値を表す2つのi32値を保持します(タプル構文)
matchを使用して各バリアントを destructure し、実行したアクションを説明するStringを return するexecutemethod を implement します。main.rs:command モジュールを取り込み、提供された inputs を使って各 command バリアントのインスタンスを1つずつ作成し、それぞれに対してexecutemethod を呼び出して results を出力します。
execute method は各バリアントを destructure してそのデータにアクセスし、次の exact な形式でメッセージを return する必要があります。
Sayの場合:Saying: {message}Moveの場合:Moving {steps} steps {direction}Calculateの場合:{a} + {b} = {sum}
出力には、各 command の result がそれぞれ独自の行に表示される必要があります。
Saying: {message}
Moving {steps} steps {direction}
{a} + {b} = {sum}たとえば、say message が "Hello world"、5 steps の Move が "north"、Calculate が 10 と 25 の場合、出力は次のようになります。
Saying: Hello world
Moving 5 steps north
10 + 25 = 355つの inputs を受け取ります:say message、direction、steps の数、そして Calculate する2つの数です。
自分で試してみよう
mod command;
use command::Command;
fn main() {
// 入力を読み取る
let mut say_message = String::new();
std::io::stdin().read_line(&mut say_message).expect("Failed to read line");
let say_message = say_message.trim().to_string();
let mut direction = String::new();
std::io::stdin().read_line(&mut direction).expect("Failed to read line");
let direction = direction.trim().to_string();
let mut steps_input = String::new();
std::io::stdin().read_line(&mut steps_input).expect("Failed to read line");
let steps: u32 = steps_input.trim().parse().expect("Failed to parse steps");
let mut num1_input = String::new();
std::io::stdin().read_line(&mut num1_input).expect("Failed to read line");
let num1: i32 = num1_input.trim().parse().expect("Failed to parse num1");
let mut num2_input = String::new();
std::io::stdin().read_line(&mut num2_input).expect("Failed to read line");
let num2: i32 = num2_input.trim().parse().expect("Failed to parse num2");
// TODO: say_message を使用して Say コマンドを作成し、実行する
// TODO: direction と steps を使用して Move コマンドを作成し、実行する
// TODO: num1 と num2 を使用して Calculate コマンドを作成し、実行する
// TODO: 各コマンド実行の結果を出力する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rustオンラインコンパイラ