強力なパターンマッチング
データのバリアントを簡潔かつ漏れなく処理するために、`match`式などのパターンマッチング構文を使いこなします。
「強力なパターンマッチング」はCoddyKit上の無料Learn Rust Codingレッスンです。 これはレッスン3/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn Rust Coding学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn Rust Codingコースには全3レッスンが含まれています。
パターンマッチングを活用する
Rustのパターンマッチングの世界へようこそ。この強力な機能を使うと、データの構造に基づいてプログラムの流れを制御できます。
単に等しいかどうかを確認するだけでなく、値を分解して構成要素を取り出し、データの形ごとに異なるコードを実行できます。
- 強力になった
if/elseやswitch文のようなものです。 - 網羅性が保証されるため、すべての可能なパターンを処理する必要があります。
- コードが読みやすく、堅牢になります。
`match` 式の基本
パターンマッチングの中心となるのが match 式です。値を受け取り、一連のパターンと比較します。最初に一致したパターンが選ばれます。
match 式の各「アーム」は、パターンと、そのパターンが一致した場合に実行するコードで構成されます。
enum Direction {
North,
East,
South,
West,
}
fn main() {
let my_direction = Direction::North;
match my_direction {
Direction::North => println!("Going up!"),
Direction::East => println!("Going right!"),
Direction::South => println!("Going down!"),
Direction::West => println!("Going left!"),
}
}リテラルと範囲のマッチング
特定のリテラル値(数値、文字、真偽値)に対してマッチングしたり、..= を使って範囲を定義したりできます。| 演算子を使うと、1つのアームで複数のパターンにマッチングできます。
パターンは順番に確認され、最初に一致したものが使われることを覚えておきましょう。
fn main() {
let x = 7;
match x {
1 => println!("It's one!"),
2 | 3 => println!("It's two or three!"),
4..=8 => println!("It's between four and eight!"),
_ => println!("It's something else!"), // Catch-all
}
let character = 'b';
match character {
'a'..='e' => println!("Early letter"),
_ => println!("Other letter"),
}
}構造体の分解
構造体のような複雑なデータ型を分解すると、パターンマッチングの真価が発揮されます。match のアーム内で、個々のフィールドを直接変数に取り出せます。
特定のフィールド値にマッチングする場合でも、構造体のデータにすっきり簡潔にアクセスできます。
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
match p {
Point { x, y: 0 } => println!("On the X axis at {}", x),
Point { x: 0, y } => println!("On the Y axis at {}", y),
Point { x, y } => println!("Not on an axis: ({}, {})", x, y),
}
}データを持つ列挙型の分解
Rustの列挙型には関連データを持たせることができます。列挙型のバリアントからこのデータを取り出す主な方法が、パターンマッチングです。
データを直接新しい変数に分解できるため、それぞれのバリアントの内容を簡単に扱えます。
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn process_message(msg: Message) {
match msg {
Message::Quit => println!("Quit message."),
Message::Move { x, y } => {
println!("Move to x: {}, y: {}", x, y);
}
Message::Write(text) => println!("Text message: {}", text),
Message::ChangeColor(r, g, b) => {
println!("Color: R:{}, G:{}, B:{}", r, g, b);
}
}
}
fn main() {
process_message(Message::Move { x: 10, y: 20 });
process_message(Message::Write(String::from("Hello!")));
}ワイルドカードパターン `_`
特殊な _(アンダースコア)パターンはすべてにマッチするパターンとして機能します。どの値にもマッチしますが、その値を束縛しません。
網羅性を満たすためにすべての可能性をカバーする必要がある一方で、特定のアームに一致した値自体には関心がない場合に便利です。
fn main() {
let some_value = Some(5);
let absent_value: Option<i32> = None;
match some_value {
Some(x) => println!("Got a value: {}", x),
_ => println!("Something else!"), // Matches None too
}
match absent_value {
Some(x) => println!("Got a value: {}", x),
_ => println!("No value here!"),
}
}単一パターン向けの `if let`
特定の1つのパターンだけに関心があり、それ以外は無視したい場合があります。このようなとき、if let は完全な match 式より簡潔な代替手段になります。
これは基本的に、「このパターンに一致したらこれを実行し、それ以外の場合は何もしない(または任意の else ブロックを実行する)」という意味です。
fn main() {
let config_max = Some(3u8);
let none_value: Option<u8> = None;
if let Some(max) = config_max {
println!("Max configured to be: {}", max);
}
if let Some(val) = none_value {
println!("This won't print: {}", val);
} else {
println!("No value found!");
}
}条件付きループ向けの `while let`
if let と同様に、while let を使うと、パターンが一致し続ける間ループできます。
これは、Vec のようなコレクションから項目を処理するときに非常に便利です。一致する要素がなくなるまで(たとえば pop() が None を返すまで)処理を続けられます。
fn main() {
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("Popped: {}", top);
}
println!("Stack is empty now.");
}マッチガード:条件を追加する
match のアームには、マッチガードと呼ばれる追加の if 条件を指定できます。そのアームを実行するには、パターンが一致し、かつガード条件が真でなければなりません。
これにより、列挙型のバリアントをさらに増やさなくても、パターン内でより細かく制御できます。
fn main() {
let num = Some(4);
match num {
Some(x) if x % 2 == 0 => println!("Even number: {}", x),
Some(x) if x < 5 => println!("Small odd number: {}", x),
Some(x) => println!("Any other number: {}", x),
None => println!("No number"),
}
}パターンマッチングのチャレンジ
次のRustコードを見てください。match 式とその出力について、次の記述のうち正しいものはどれでしょうか。
enum Status {
Loading,
Success(u32),
Error(String),
}
fn process_status(s: Status) {
match s {
Status::Success(code) if code > 200 => println!("Success with high code: {}", code),
Status::Success(code) => println!("Success with code: {}", code),
Status::Error(msg) => println!("Failed: {}", msg),
_ => println!("Status unknown or loading..."),
}
}
fn main() {
process_status(Status::Success(201));
process_status(Status::Error(String::from("Network issue")));
process_status(Status::Loading);
process_status(Status::Success(200));
}振り返り:パターンを使いこなす
Rustのパターンマッチングが持つ素晴らしい力を学びました。これは、明確で簡潔かつ安全なコードを書くための基本概念です。
match式は、データ構造に基づく網羅的なフロー制御を提供します。- リテラルや範囲、ワイルドカード(
_)を使ってマッチングできます。 - 分解により、構造体や列挙型から値を直接取り出せます。
if letとwhile letを使うと、単一パターンに対して簡潔にマッチングできます。- マッチガードを使うと、
matchのアームに条件ロジックを追加できます。
これらのパターンを練習し続けましょう。Rustらしいコードを書くために欠かせないものです。
よくある質問
「強力なパターンマッチング」レッスンは無料ですか?
はい。「強力なパターンマッチング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn Rust Codingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn Rust Codingコースには全3レッスンが含まれています。
「強力なパターンマッチング」で何を学びますか?
データのバリアントを簡潔かつ漏れなく処理するために、`match`式などのパターンマッチング構文を使いこなします。 ブラウザで直接実行するハンズオンコードでLearn Rust Codingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Learn Rust Codingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLearn Rust Codingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/3です。
「強力なパターンマッチング」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLearn Rust Codingレッスンでコードを書いて実行できますか?
はい。すべてのLearn Rust Codingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 構造体の定義と利用
- カスタム型のための列挙型
- 強力なパターンマッチング