迴圈 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,總共執行五次;每次都在字串 welcome to FoxDevelop.com 尾端拼接驚嘆號!

第一次 welcome to FoxDevelop.com!

第二次 welcome to FoxDevelop.com!!

第五次 welcome to FoxDevelop.com!!!!!

特性:閉包獨立綁定索引(與 JS 重大差異)

Dart 每次迴圈都會綁定獨立的 i 變數,不會發生 JavaScript 全部輸出 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 方法;取值完自動切換至下一個元素。

進階用法

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

先判斷條件再執行主體(有可能完全不執行),邏輯與 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 次)

bool atEndOfPage() => true;
void printLine() => print("印出一行");

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

無論 while 後方條件為 true 或 false,do {} 大括號內程式一定會執行一次。

五、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

直接跳出雙層迴圈

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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *