【Dart入門(6)】制御フロー|条件分岐(if else, if case)
Dartの制御フローについて
dartの制御フローには以下のようなものが存在します。
制御フロー一覧
- 分岐
- if
- Aが〜と等しい時
- Aの中に〜がない時など
- if else if else:
- Aが〜でなくて**の時など条件を複数使用した時(多すぎる時はswitch文の方が可読性が高い)
- if case
- Aが〜な型の時
- Aを分解したい時(後で説明します)
- if case when
- Aが〜な型の時で、各要素に対して**が成立するときなど
- switch
- Aが〜なケースの時などケースが複数ある時に使用
- if
- ループ
- for
- 一定回数繰り返したい時
- 要素を取り出して各々に操作をしたい時
- while
- 先に条件判定して、条件を満たすまでループさせたい時
- do while
- 先に実行して、条件を満たすまでループさせたい時
- break, continue(ループ処理の中で用いる)
- for
- 例外処理
- try, on, catch
- on: 予期している例外に対処する
- catch: 予期しない例外に対処する
- try, on, catch
これらの制御フローは今すぐ理解する必要はありませんが、なんとなくこういうのがあるのかと認識しておくことが大切です。
分岐を詳しく見ていく
分岐にはif
とif case
とswitch case
が存在します。
if, if else if else文
if
文は以下のように使用します
if (条件文) {
処理
}
具体的に例を見ていきましょう。
変数aが1である場合、print(a)を実行する場合は以下のようになります。この場合、aが2とか1以外の数字なら何も出力されません。
int a = 1;
if (a == 1) {
print(a);
}
// 1
次にif else if else
を見ていきましょう
使い方
if (条件A) {
処理
} else if (条件B) {
処理
} else {
処理
}
具体例
int a = 3;
if (a.isEven) {
print(a);
} else if (a.isNegative) {
print("a is negative and even number: ${a}");
} else {
print("a is positive and odd number: ${a}");
}
これがif else文です。
if
文とif else
文は頻出なので覚えておきましょう。
if case, if case when文
if case
文はパターンマッチングです。〜な型の時といった条件で分岐させたい時に使用します。
前回のCollectionなどでよく使用します。先ほどと異なるのは、オブジェクトが等しいなどではなくパータンにマッチしているかどうか?という点です。
使用方法
if (変数 case パターンマッチング) {
処理
}
このパターンマッチングですがdartにはいくつかのパターンマッチングが存在します。
dartのパターンマッチングの種類
- 論理和パターン
- 論理積パターン
- リレーショナルパターン
- nullチェックパターン
- 定数パターン
- 変数パターン
- 識別子パターン
- 括弧パターン
- リストパターン
- Mapパターン
- Recordパターン
- オブジェクトパターン
- ワイルドカード
これら全てを今すぐ使いこなすのは難しいのでよく使用する型のマッチングパターン(Record, オブジェクト、Map)と変数の等価性や大小、包含性を比較するパターン(変数、定数、論理和、論理積、リレーショナル)を具体例で見ていきましょう。
まず型のマッチングパターンについて。
1) List パターン
final list = [1, 2, 3];
// 先頭2要素だけ取りたい
if (list case [int a, int b, ...]) {
print('a=$a, b=$b'); // a=1, b=2
}
// 2要素ちょうどの場合だけ
if (list case [int x, int y]) {
// ここは list.length == 2 の時だけ入る
}
-
...
は「残り要素があってもよい」を表す(“残余”)。 - 使わない要素は
_
(ワイルドカード)で捨てられる。
2) Record パターン
Record は 位置(positional) と 名前付き(named) の両方を持てます。パターンでも同様に分解できます。
final rec = (1, b: 'sample', c: false, 5);
// 位置2つ + 名前付き2つを分解
if (rec case (int first, int _, b: String b, c: bool c)) {
print('first=$first, b=$b, c=$c'); // first=1, b=sample, c=false
}
ポイント
- 位置成分は並び順で、名前付き成分は
name: pattern
で指定します。 - 使わない位置成分は
int _
のように型だけ書いて_
で破棄可。 -
型検査 + 変数束縛 を一度にやるには
String b
/bool c
のように “型 + 変数名” と書きます。
3) オブジェクトパターン
クラスの ゲッター名 で分解します。「プロパティ名: サブパターン」の形。このサブパターンはプロパティに対してパターンを適用することができるということです。
class User {
final String name;
final int age;
const User(this.name, this.age);
}
final obj = User('Alice', 20);
// 年齢が 18 超 & 名前を取り出す
if (obj case User(name: var n, age: > 18)) {
print('$n is adult user'); // Alice is adult user
}
-
User(name: var n, age: > 18)
は-
name
をvar n
で 束縛(取り出し) -
age
に リレーショナルパターン> 18
を適用
-
- いずれもゲッター(ここでは
name
,age
)経由で判定・抽出されます。
4) Map パターン
特定のキーが存在していて、その値がパターンにマッチするかを確認できます。
final map = {
'a': 1,
's': 'hello',
};
// キー 'a' は int、's' は String を期待して分解
if (map case {'a': int a, 's': String text}) {
print('a=$a, text=$text'); // a=1, text=hello
}
// 余計なキーがあってもよい(厳密一致にしない)
if (map case {'a': int _ , ...}) {
print('has a'); // 'a' が int なら入る
}
ポイント
-
{'k': pattern}
の形で値側をさらに分解できます(String text
など)。 -
...
を置くと “他のエントリがあってもよい” になります。
次に比較パターンについて
比較系のパターン
1) 変数パターン / 定数パターン
final x = 0;
// 定数パターン(等価比較)
if (x case 0) {
print('zero');
}
// 変数パターン(束縛)— if-case ではあまり単独では使わないが、入れ子で使う
Object any = 'hi';
if (any case String s) { // 型パターン + 変数束縛
print(s.toUpperCase()); // HI
}
2) リレーショナルパターン(大小関係)
int n = 7;
if (n case >= 0 && <= 10) { // 0〜10 の範囲か
print('in range');
}
if (n case != 5) { // 等しくない
print('not five');
}
-
<, <=, >, >=, ==, !=
が使えます。 -
&&
は 論理積パターン、複数条件を「かつ」で繋げられます。
3) 論理和パターン / 論理積パターン
final ch = 'Y';
// Y か y のどちらか(論理和)
if (ch case 'Y' || 'y') {
print('yes');
}
if
と if case
の違い
-
if (条件式)
… いつものブール式。 -
if (値 case パターン)
… パターンにマッチするかをテストして、同時に分解・束縛までやる。
マッチしたときにだけ、パターン内で束縛した変数(a
,b
,text
など)が if ブロック内で使える。
まとめ
以上がdartで用いられるif else
とif case
の使用方法です。特に後者の方は慣れない概念だと思いますが、なんか使えそうだと思った時に使用してみようといった感じで問題ないと思います!
Discussion