一、if / if-else 基本分岐
if丸括弧の中身は必ず真偽値式にする必要があり、暗黙的な真偽型への変換は許可されませんelse ifを複数連ねて記述でき、最後に任意でelseを追加可能- 処理が1行だけの場合は波括弧を省略できますが、可読性のため全部括弧を付ける習慣が推奨されます
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("レインコートを持っていく");
} else if (isSnowing) {
print("厚手の上着を着る");
} else {
print("オープンカーでドライブ");
}
}Code language: Dart (dart)
実行結果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
厚手の上着を着るCode language: CSS (css)
if 単体だけで使用することもできます
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("レインコートを持っていく");
}
}Code language: Dart (dart)
あるいは if else だけの記述も可能
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("レインコートを持っていく");
} else {
print("オープンカーでドライブ");
}
}Code language: Dart (dart)
二、if-case パターンマッチ分岐(Dart3.0以降対応)
- パターンに適合した場合、変数をデストラクチャリングして現在のスコープに束縛します
- マッチに失敗したら else へ移行。
whenガードを追加して追加の真偽判定を書けます - 単一の値に単一パターンを照合する構文のため、複数パターンの分岐には switch を使います
void main() {
final pair = [100, 220];
// 要素2つ、両方int型の配列にマッチ
if (pair case [int x, int y]) {
print("座標:$x,$y");
} else {
throw FormatException("不正な座標");
}
}Code language: Dart (dart)
実行結果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
座標:10,20Code language: CSS (css)
2:when ガードと組み合わせた if-case
void main() {
final data = [8, 9];
if (data case [int a, int b] when a > 5 && b > 5) {
print("二つの数が両方5より大きい");
} else {
print("数値が条件を満たしていない");
}
}Code language: Dart (dart)
実行結果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
二つの数が両方5より大きいCode language: CSS (css)
三、switch 文
従来型のswitchは文形式で、戻り値を持ちません
- caseには文字列、定数、論理OR、関係演算子パターンなど任意のパターンを指定可能
- 中身のあるcaseは自動的にbreakするため手動でbreakを書く必要なし。空のcaseは自動でフォールスルーします
- 手動でフォールスルーさせる方法は2種類:
continue ラベル/ 空のcaseを連続記述 - どのcaseにも一致しなかった場合
defaultが実行。whenガードに対応
1:基本的な文字列マッチ
void main() {
String command = "OPEN";
switch (command) {
case "CLOSED":
print("クローズ処理を実行");
case "PENDING":
print("待機処理を実行");
case "OPEN":
print("オープン処理を実行");
default:
print("不明なコマンド");
}
}
Code language: Dart (dart)
実行結果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
オープン処理を実行Code language: CSS (css)
2:空caseによるフォールスルー + continueラベルでのジャンプ
String command = "OPEN";
switch (command) {
case "OPEN":
print("オープン操作"); // ① OPENにマッチし出力
continue newCase; // ② newCaseラベルへ直接ジャンプ、戻らない
case "DENIED":
case "CLOSED":
print("クローズ操作");
newCase: // ③ ジャンプ先ラベル
case "PENDING":
print("共通の保留処理"); // ④ command == "PENDING" の判定をスキップして即実行
}Code language: Dart (dart)
実行結果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
オープン操作
共通の保留処理Code language: CSS (css)
この例で
continue newCase;はnewCaseラベルへ飛ぶとしても、直後のcase “PENDING”にはマッチしないはずなのに、なぜ print(“共通の保留処理”); が実行されるのでしょうか?多くの読者が抱く疑問点です
continue ラベル; は値を再照合せず、ラベルのあるcase分岐の入口へ直接ジャンプし、条件判定を省略して分岐内コードを即実行します。
3:switch + when ガード
void main() {
int score = 88;
switch (score) {
case int s when s >= 90:
print("優秀");
case int s when s >= 60:
print("合格");
default:
print("不合格");
}
}
Code language: Dart (dart)
出力:合格
まず型がintか確認し、intならsに値を代入。その後whenガードで2次判定を行い、条件を満たした場合のみcase内の文が実行されます。ここの二箇所のint sはそれぞれスコープが独立し干渉しません。
各 case int s は独立したパターン束縛で、変数の有効範囲は自身のcase内だけに限定されます
二つのcaseで別々の変数名を使っても動作は完全に同じです。
switch (score) {
case int a when a >= 90:
print("優秀");
case int b when b >= 60:
print("合格");
default:
print("不合格");
}Code language: Dart (dart)
四、switch 式
Dart3.0以降で利用可能な構文で、戻り値を持ち変数代入によく使われます
switch文との違い
caseキーワードがなく、=>でパターンと式を区切る- 各分岐は必ず式を返し、分岐同士をカンマで区切る
- 暗黙的なフォールスルーはなく各分岐が独立。一致するものがない場合はアンダースコア
_を使用、defaultは使えない - 代入、print、returnなどあらゆる式コンテキストで直接利用可能
1:基本文字演算子マッチ(論理ORパターン)
void main() {
const slash = 47, star = 42, comma = 44;
int charCode = 42;
final token = switch (charCode) {
slash || star => "演算子",
comma => "句読点",
_ => "無効文字"
};
print(token);
}
Code language: Dart (dart)
実行結果
演算子
このサンプルでは3種類の記号のASCIIコードを定数として定義し、charCode変数の値が演算子・句読点・その他のどれに該当するか判定しています。
2:switch式 + whenガード
void main() {
int age = 22;
String level = switch (age) {
int a when a < 18 => "未成年",
int a when a < 30 => "青年",
_ => "成人"
};
print(level);
}Code language: Dart (dart)
実行結果
青年
3:関数のreturn内でswitch式を直接使用
void main() {
print(getDesc(3));
}
String getDesc(int num) => switch (num) {
1 => "一",
2 => "二",
_ => "その他の数字"
};
Code language: Dart (dart)
実行結果
その他の数字
補足:ここのswitchは式であり、getDescはアロー関数です。アロー関数は他のC系言語にはないDart独自の文法です。
五、網羅性チェック Exhaustiveness Checking
入力値に対応する分岐が不足しているとコンパイルエラーが発生し、不足したcaseを補完するよう強制されます。sealedクラス・enum列挙型はデフォルトで網羅チェックに対応し、_ やdefaultによるフォールバックが不要です。
1:Nullable真偽値による網羅漏れエラー(コメントアウトして実行するとエラーを確認可能)
void main() {
bool? nullableBool = null;
// 下記コードのコメントを外すとコンパイルエラー:nullに対応するcaseがなく、_/defaultによる補完もないため
/*
switch (nullableBool) {
case true:
print("真");
case false:
print("偽");
}
*/
// 修正方法:null用caseを追加、または_で補完
switch (nullableBool) {
case true:
print("真");
case false:
print("偽");
case null:
print("null値");
}
}Code language: PHP (php)
実行結果
null値
2:sealed 密封クラス
代数的データ型で、完全な網羅マッチを強制します
import 'dart:math' as math;
// sealedクラス:サブクラスは同一ファイル内でのみ定義可能
sealed class Shape {}
// サブクラス 正方形:辺の長さ
class Square implements Shape {
final double length;
Square(this.length);
}
//サブクラス 円:半径
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
// 渡されたサブクラスオブジェクトをswitchで判定し面積を計算するアロー関数
double calculateArea(Shape shape) => switch (shape) {
Square(length: var l) => l * l,
Circle(radius: var r) => math.pi * r * r
// Shapeに新しいサブクラスを追加すると、対応するcaseが不足しコンパイルエラーになる
};
void main() {
final Shape circle = Circle(5);
print(calculateArea(circle));
final Shape square = Square(4);
print(calculateArea(square));
}
Code language: Dart (dart)
実行結果
78.53981633974483
16.0Code language: CSS (css)
3:Enum列挙型の網羅マッチ
フォールバック用のアンダースコア_ が不要
void main() {
final Animal animal = Animal.cat;
String name = switch (animal) {
Animal.dog => "犬",
Animal.cat => "猫"
};
print(name);
}
enum Animal { dog, cat }
Code language: Dart (dart)
出力:猫
enumは値の範囲が固定され未知の値が発生しないため、フォールバック分岐を用意する必要がありません。
六、when ガード
if-case / switch文 / switch式の全構文で利用可能
whenの役割:パターンマッチ成功後に追加の真偽判定を実行。ガードの結果がfalseの場合、switchを抜けず次の分岐へ進みます。
1. if-case + when
void main() {
List<int> arr = [10, 20];
if (arr case [int x, int y] when x + y > 20) {
print("二数の合計が20を超える");
}
}Code language: Dart (dart)
二数の合計が20を超える
まず2つのint型を持つ配列か判定し、適合したらwhenで合計が20超えるか再確認します
2. switch文 + when
void main() {
int num = 15;
switch(num) {
case int n when n % 2 == 0:
print("偶数");
case int n when n % 2 != 0:
print("奇数");
}
}
Code language: PHP (php)
出力:奇数
先にint型か判定し、その後when内の条件を確認します。
3. switch式 + when
void main() {
int num = 15;
String res = switch(num) {
int n when n % 2 == 0 => "偶数",
_ => "奇数"
};
print(res);
}
Code language: PHP (php)