ループ Loops

一、標準 for ループ

文法:for(初期化; 条件; 反復処理) { ループ本体 }

1:基本文字列連結

void main() {
  var message = StringBuffer('welcome to FoxDevelop.com');
  for (var i = 0; i < 5; i++) {
    message.write('!');
  }
  print(message); // welcome to FoxDevelop.com!!!!!
}Code language: Dart (dart)

0から5まで(5を含まない)ループするという意味で、iは0~4の値を取り、計5回実行されます。毎回文字列末尾に「!」を追加します。

1回目 welcome to FoxDevelop.com!

2回目 welcome to FoxDevelop.com!!

5回目 welcome to FoxDevelop.com!!!!!

特徴:クロージャが独立したインデックスを保持(JavaScriptとの重要な違い)

Dartはループごとに独立したi変数をバインドするため、JSのように全部2が出力される不具合が起きません。

void main() {
  var callbacks = [];
  for (var i = 0; i < 2; i++) {
    callbacks.add(() => print(i));
  }
  for (final c in callbacks) {
    c();
  }
}
// 出力
// 0
// 1
Code language: Dart (dart)

二、for-in 反復可能オブジェクト List/Set の走査

インデックスが不要で値だけ取得したい場面に適しています。

基本記述

class Candidate {
  void interview() => print("面接完了");
}

void main() {
  var candidates = [Candidate(), Candidate()];
  for (var candidate in candidates) {
    candidate.interview();
  }
}Code language: Dart (dart)

candidates配列を走査し、要素をcandidate変数に代入してinterviewメソッドを呼び出します。1要素処理後は自動で次の要素へ進みます。

応用

for-in とオブジェクトパターン分解(Dart3以降)

class Candidate {
  final String name;
  final int yearsExperience;
  Candidate({required this.name, required this.yearsExperience});
}

void main() {
  var candidates = [
    Candidate(name: "Lily", yearsExperience: 6),
    Candidate(name: "Tom", yearsExperience: 3),
  ];

  // オブジェクトパターンでフィールドを直接分解
  for (final Candidate(:name, :yearsExperience) in candidates) {
    print('$name は勤務年数 $yearsExperience 年');
  }
}
Code language: Dart (dart)

先ほどのパターン分解と組み合わせ、オブジェクト内のプロパティを自動的にname、yearsExperience変数に取り出し、ループ内で使用できます。

三、Iterable.forEach () 走査メソッド

コレクション標準の関数型走査メソッド。コールバックを渡して各要素を処理します。

void main() {
  var collection = [1, 2, 3];
  collection.forEach(print);
  // 出力 1 2 3
}Code language: Dart (dart)

forEachはDart標準メソッドで、すべての反復可能コレクションから呼び出せます。

四、while /do-while

1. while

条件判定を先に行ってから本体を実行するため、1回も実行されない場合があります。C/C++/Java/C#など他言語と動作が同じです。

bool isDone() => false;
void doSomething() => print("タスク実行");

void main() {
  while (!isDone()) {
    doSomething();
    break;
  }
}Code language: Dart (dart)

!isDone()を評価すると、元の戻り値がfalseなので否定してtrueとなり、中身が実行されます。

doSomething();
break;

breakに到達するとループ全体が終了し、whileブロックの後ろへジャンプします。もしisDone()がtrueを返す場合、最初の判定で条件に合わず中身は一度も動きません。

2. do-while

本体を必ず1回実行した後に条件判定を行うため、最低1回は処理が走ります。

bool atEndOfPage() => true;
void printLine() => print("1行出力");

void main() {
  do {
    printLine();
  } while (!atEndOfPage());
}
Code language: Dart (dart)

後ろのwhile条件がtrue/falseどちらでも、do {}内のコードは必ず1回実行されます。

五、break /continue

break

ループ全体を即時終了し、ループ後の処理へ移動。ループ内の残りコードは実行されません。

bool shutDownRequested() => true;
void processIncomingRequests() => print("リクエスト処理");

void main() {
  while (true) {
    if (shutDownRequested()) break;
    processIncomingRequests();
  }
  print("ループ終了");
}
Code language: Dart (dart)

continue

現在の反復の残りコードをスキップし、直ちに次のループへ移行します。

従来のfor記述
class Candidate {
  final int yearsExperience;
  Candidate(this.yearsExperience);
  void interview() => print("面接実施");
}

void main() {
  var candidates = [Candidate(3), Candidate(6)];
  for (int i = 0; i < candidates.length; i++) {
    var candidate = candidates[i];
    if (candidate.yearsExperience < 5) {
      continue; // 勤続5年未満は面接をスキップ
    }
    candidate.interview();
  }
}
Code language: Dart (dart)
関数型による代替(continue不要)
void main() {
  var candidates = [Candidate(3), Candidate(6)];
  candidates
      .where((c) => c.yearsExperience >= 5)
      .forEach((c) => c.interview());
}
Code language: Dart (dart)

六、ラベル Label による入れ子ループ制御

文法:ラベル名: をループ先頭に記述し、break ラベル / continue ラベル と組み合わせて使用

用途:多重入れ子ループ時、内側だけでなく外側ループを直接脱出・スキップできる

1. break + label

2重ループを一気に脱出

void main() {
  outerLoop:
  for (var i = 1; i <= 3; i++) {
    for (var j = 1; j <= 3; j++) {
      print('i = $i, j = $j');
      if (i == 2 && j == 2) {
        break outerLoop; // outerLoopと名付けた外側ループを強制終了
      }
    }
  }
  print('outerLoop exited');
}
Code language: Dart (dart)

出力:

i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 2, j = 2
outerLoop exited
Code language: Dart (dart)

2. continue + label

外側ループの次の反復へ直接移行

void main() {
  outerLoop:
  for (var i = 1; i <= 3; i++) {
    for (var j = 1; j <= 3; j++) {
      if (i == 2 && j == 2) {
        continue outerLoop; // i=2の残りjを全スキップ、i=3へ移る
      }
      print('i = $i, j = $j');
    }
  }
}
Code language: Dart (dart)

出力:

i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 3, j = 1
i = 3, j = 2
i = 3, j = 3

while+break+label 例

void main() {
  var i = 1;
  outerLoop:
  while (i <= 3) {
    var j = 1;
    while (j <= 3) {
      print('i = $i, j = $j');
      if (i == 2 && j == 2) {
        break outerLoop;
      }
      j++;
    }
    i++;
  }
  print('outerLoop exited');
}
Code language: PHP (php)

実行結果

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
i = 1, j = 1
i = 1, j = 2
i = 1, j = 3
i = 2, j = 1
i = 2, j = 2
outerLoop exited

他言語のgotoに似た動作をします。

ループ Loops

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です