
条件分岐(if / switch、pattern)
この節の目的は、「場合によって処理を変える」 というプログラムの基本感覚を身につけることです。第2章では、2-2 で変数・型・null safety・List / Map を学びました。今回はその続きとして、入ってきた値を見て、どの処理を動かすかを決める方法を学びます。Dart では昔ながらの if と switch に加えて、Dart 3 から patterns パターン が本格的に入り、switch や if case で「値の形そのもの」を見て分岐できるようになりました。Patterns は Dart 3.0 以上で使え、Dart 3 は 2023年5月10日に公開されました。
1. 条件分岐とは何か
条件分岐とは、条件が成り立つかどうかで処理を変えることです。
たとえば、テストの点数が 60 点以上なら「合格」を表示し、それ未満なら「再提出」を表示する、という動きです。人は日常で自然にこれをやっています。雨なら傘を持つ。電車が遅れていたら別ルートを考える。プログラムでは、その判断を明示的に書きます。
歴史的には、if ... then ... else ... という考え方は 1960 年の ALGOL 60 の報告書にすでに見られます。ALGOL 60 は国際的なアルゴリズム記述言語として設計され、条件式や条件文を体系的に扱いました。つまり、いま私たちが書く if は、かなり古くからある「プログラムの基本構造」です。
2. if 文の基本
最初に学ぶのは if です。
if は、「もし条件が真ならこの処理をする」という最も基本的な分岐です。
void main() {
int score = 78;
if (score >= 60) {
print('合格です');
}
}
このコードでは、score >= 60 が真なら 合格です を表示します。>= は「以上」という意味です。78 は 60 以上なので、表示されます。
ここで大事なのは、if の丸かっこの中には true か false になる式 を書くことです。
Dart は型安全な言語なので、他の一部言語のように数字をそのまま条件として扱いません。条件には bool 型、つまり真偽値になる式が必要です。Dart 公式も、分岐は boolean conditions を使う形で説明しています。
3. if / else で二択を作る
「条件が真のとき」だけではなく、「そうでないとき」も書きたい場合は else を使います。
void main() {
int score = 45;
if (score >= 60) {
print('合格です');
} else {
print('再提出です');
}
}
このコードでは、score が 60 未満なので 再提出です が表示されます。
初心者が最初につまずきやすいのは、「どちらか片方しか実行されない」ことです。
if と else は競争ではなく、一つの条件に対して二つの道を用意する イメージです。
学校の例で考えると分かりやすいです。
- 宿題が終わっていたらゲームする
- 終わっていなければ宿題を続ける
この「もし〜なら、そうでなければ〜」が、そのまま if / else です。
4. else if で三択以上を作る
現実の判断は二択だけではないことが多いです。
たとえば、点数によって「優秀」「合格」「再提出」を分けたいことがあります。
そういうときは else if を使います。
void main() {
int score = 88;
if (score >= 90) {
print('とても良いです');
} else if (score >= 60) {
print('合格です');
} else {
print('再提出です');
}
}
この場合、score は 88 なので、最初の score >= 90 は false です。
次の score >= 60 は true なので、合格です が表示されます。
ここで覚えておきたいのは、上から順に判定され、最初に当てはまったところで止まる ということです。
だから順番はとても大切です。
次のように順番を間違えると、意図した結果になりません。
void main() {
int score = 95;
if (score >= 60) {
print('合格です');
} else if (score >= 90) {
print('とても良いです');
} else {
print('再提出です');
}
}
このコードでは 95 点でも最初の score >= 60 に当たるので、合格です が表示されます。
つまり、広い条件を先に書くと、細かい条件が届かなくなる のです。
5. switch 文とは何か
switch は、一つの値を複数の候補と比べて分岐する ときに便利です。
たとえば、曜日によって表示を変えるとき、メニュー番号ごとに動作を変えるとき、状態コードごとに処理を変えるときに向いています。
歴史をたどると、分岐を多枝に広げる考え方は古く、ALGOL 68 の改訂報告では、ALGOL 60 の conditional clause を一般化して case-clause にしたと説明されています。さらに、C 言語の系譜では、Dennis Ritchie の C Reference Manual に switch statement がはっきり記述されており、C 系言語で広く知られる形になっていきました。
Dart 公式では、switch は「値を一連の cases に対して評価する構文」で、各 case 句は pattern であると説明されています。つまり、今の Dart の switch は、昔ながらの「値の比較」だけでなく、「値の形の照合」までできる構文です。
6. switch 文の基本
まずは、一番シンプルな switch から見ます。
void main() {
String command = 'OPEN';
switch (command) {
case 'OPEN':
print('開く処理をします');
case 'CLOSE':
print('閉じる処理をします');
default:
print('不明なコマンドです');
}
}
このコードでは command が 'OPEN' なので、開く処理をします が表示されます。
Dart の modern switch で大事なのは、空でない case は終わったら switch の外へ抜ける ことです。
C 系言語でよく出てくる break を毎回書かなくてもよい、という点は初心者にとってかなり助かります。Dart 公式も、non-empty case clauses do not require a break statement と説明しています。
7. switch が向いている場面
if / else if でも同じことはできます。
では、なぜ switch があるのでしょうか。
答えは、一つの値を、複数の決まった候補と比べるときに読みやすいからです。
たとえば、曜日番号を文字に変える例を見てください。
void main() {
int day = 3;
switch (day) {
case 1:
print('月曜日');
case 2:
print('火曜日');
case 3:
print('水曜日');
case 4:
print('木曜日');
case 5:
print('金曜日');
default:
print('土日または不正な値');
}
}
これは if / else if でも書けますが、switch のほうが「候補の一覧」を見やすいです。
つまり、if は「条件そのもの」を書くのが得意で、switch は「候補を並べる」のが得意です。
8. pattern とは何か
ここで Dart らしい新しい話が出てきます。
それが pattern パターン です。
Dart 公式では、pattern は「値が持つ形 shape を表し、それに実際の値が一致するかを調べるもの」と説明されています。さらに pattern は、値を match させるだけでなく、destructure 分解して中身を取り出す こともできます。Patterns は Dart 3.0 以上で使えます。
もう少しかみくだくと、pattern は
「この値は、こういう形をしているはずだ」
という期待を書ける仕組みです。
歴史的には、pattern matching の考え方は関数型言語の流れで強まりました。
2020 年の The History of Standard ML は、Standard ML が datatypes with associated case analysis by pattern matching を popularize したと説明しています。つまり、パターンマッチは関数型言語で大きく育ち、その考え方が Dart にも入ってきたと見てよいです。
9. Dart の pattern をやさしく体験する
9-1. if case
Dart では if case が使えます。
これは「if しながら pattern で照合する」構文です。
void main() {
var pair = [10, 20];
if (pair case [int x, int y]) {
print('x = $x, y = $y');
} else {
print('2つの整数ではありません');
}
}
このコードでは、pair が「整数が2個入った List の形」なら、x と y に取り出します。
Dart 公式にも if (pair case [int x, int y]) の例があります。
ここでの面白い点は、一致するかどうかを見ながら、同時に中身を取り出せる ことです。
これが pattern の強さです。
9-2. switch と pattern
switch でも pattern が使えます。
void main() {
var value = [1, 2];
switch (value) {
case [int a, int b]:
print('2つの整数です: $a, $b');
default:
print('別の形です');
}
}
このコードは、value が「整数2個の List」なら、その中身を a と b に分けて表示します。
昔ながらの switch は「1 ならこれ、2 ならこれ」という比較が中心でした。
今の Dart の switch は、値の中身の形まで見られる のが大きな進化です。
この考え方は、後で records やより複雑なデータ構造を扱うときに強く効いてきます。
10. if と switch と pattern の使い分け
ここまで来ると、三つの違いを整理したくなります。
if が向いているとき
- 条件が比較や論理式で表せるとき
score >= 60のように、範囲や複雑な条件を書くとき- 「A かつ B」のような条件を作るとき
switch が向いているとき
- 一つの値を、複数候補と比べるとき
- メニュー番号、状態コード、曜日番号など
- 候補の一覧を見やすく書きたいとき
pattern が向いているとき
- 値の「形」を見たいとき
- List や records の中身を分解したいとき
- 一致確認と取り出しを同時にしたいとき
迷ったら
- 単純な条件なら
if - 候補一覧なら
switch - 値の形まで見たいなら
pattern
11. 飽きずに分かるミニ実践
実践1:テスト判定
void main() {
int score = 72;
if (score >= 80) {
print('とても良いです');
} else if (score >= 60) {
print('合格です');
} else {
print('再提出です');
}
}
実践2:曜日表示
void main() {
int day = 5;
switch (day) {
case 1:
print('月曜日');
case 2:
print('火曜日');
case 3:
print('水曜日');
case 4:
print('木曜日');
case 5:
print('金曜日');
default:
print('土日または不正な値');
}
}
実践3:座標の形を確認する
void main() {
var point = [3, 7];
if (point case [int x, int y]) {
print('座標は ($x, $y) です');
} else {
print('座標データではありません');
}
}
この 3 つを見ると、
if は条件、switch は候補、pattern は形、
という違いがかなり見えやすくなります。
12. 練習問題
問題1
次のコードは何を表示しますか。
void main() {
int score = 61;
if (score >= 60) {
print('合格');
} else {
print('再提出');
}
}
問題2
次のコードは何を表示しますか。
void main() {
String weather = 'rain';
switch (weather) {
case 'sunny':
print('晴れです');
case 'rain':
print('雨です');
default:
print('不明です');
}
}
問題3
次のコードで、else if が必要な理由を一文で説明してください。
void main() {
int score = 95;
if (score >= 90) {
print('A');
} else if (score >= 60) {
print('B');
} else {
print('C');
}
}
問題4
次のコードは何を表示しますか。
void main() {
var data = [5, 8];
if (data case [int x, int y]) {
print(x + y);
} else {
print('no');
}
}
問題5
if、switch、pattern のうち、次の場面に一番向くものを選んでください。
- 点数が 60 点以上かどうかを判定したい
- メニュー番号 1〜4 に応じて処理を変えたい
- List に整数が 2 個入っているか確認し、中身を取り出したい
13. 練習問題の答え
答え1
合格 が表示されます。61 >= 60 が true だからです。
答え2
雨です が表示されます。
weather が 'rain' なので、その case に一致します。Dart の switch は、値を case に対して評価して一致した本体を実行します。
答え3
90 点以上を先に判定し、その次に 60 点以上を判定したいからです。
もし score >= 60 を先に書くと、95 点でも先にそちらへ当たってしまいます。
答え4
13 が表示されます。data は [int x, int y] の形に一致するので、x = 5、y = 8 となり、x + y は 13 です。Patterns は match と destructure を同時に行えます。
答え5
ifswitchpattern
14. まとめ
この節では、条件分岐の三つの顔を学びました。
if は、条件式で分ける基本構文です。
switch は、一つの値を複数候補と比べるときに読みやすい構文です。
そして pattern は、値の「形」を見て、一致確認と中身の取り出しを同時にできる仕組みです。Dart 3 では patterns が正式に入り、switch の case も pattern として扱われるようになりました。
歴史をふり返ると、条件分岐は 1960 年の ALGOL 60 の時代から重要な概念でした。多枝分岐は ALGOL 68 の case-clause や、Dennis Ritchie が文書化した C の switch statement を通じて広く普及しました。さらに pattern matching の考え方は Standard ML が大きく広め、その流れが今の Dart にも入っています。つまり、いま書いている if や switch や pattern は、バラバラの新機能ではなく、長いプログラミング言語の歴史の上に並んでいるのです。
次節では、今度は「同じ処理をくり返す」ためのループ処理を学びます。条件で道を分ける感覚がつかめると、ループの中で条件を使う場面もかなり読みやすくなります。
参考文献
- https://dart.dev/language/branches
- https://dart.dev/language/patterns
- https://blog.dart.dev/announcing-dart-3-53f065a10635
- https://www.softwarepreservation.org/projects/ALGOL/report/Algol60_revised_report_CACM.pdf
- https://www.softwarepreservation.org/projects/ALGOL/report/Algol68_revised_report-AB-600dpi.pdf
- https://www.bell-labs.com/usr/dmr/www/cman.pdf
- https://smlfamily.github.io/history/SML-history.pdf