分支控制流程

一、if / if-else 基礎分支

  1. if 括號內必須放置布林運算式,不允許自動隱式轉換布林值
  2. 支援多個 else if 區塊,末尾可選擇性加上 else
  3. 單行程式碼可省略大括號,但建議一律加上大括號提升可讀性
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 以上適用)

  1. 進行模式比對,比對成功時會解構綁定變數至當前作用域
  2. 比對失敗會進入 else;可搭配 when 守衛新增布林判斷條件
  3. 僅適用於單一值配單一模式場景,多模式比對請改用 switch
void main() {
  final pair = [100, 220];
  // 比對長度為2、內含兩個整數的陣列
  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.
兩個數字皆大於5Code language: CSS (css)

三、switch 陳述式

傳統 switch 為陳述式語法,沒有回傳值

  1. case 支援各種模式:字串、常數、邏輯或、關係運算模式
  2. 有內容的 case 會自動中斷,不需手動撰寫 break;空 case 會自動穿透往下執行
  3. 手動實現穿透有兩種方式:continue 標籤 或是連續撰寫空 case
  4. 所有 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)

輸出及格

程式會先比對型別,確認輸入為整數後將值賦予變數 s,接著透過 when 守衛做二次檢驗,只有 s 符合 when 後的條件才會執行該 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 陳述式差異

  1. 不需 case 關鍵字,以 => 分隔模式與回傳運算式
  2. 每個分支必須回傳運算式,多分支使用逗號隔開
  3. 無隱式穿透,各分支獨立;無任何匹配時使用底線符 _ 作兜底,不能使用 default
  4. 可直接用於賦值、列印、函式回傳,適用所有運算式場景

1:基礎字元運算子比對(邏輯或模式)

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)

執行結果

運算子

本範例定義三個符號 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:函式回傳直接使用 switch 運算式

void main() {
  print(getDesc(3));
}

String getDesc(int num) => switch (num) {
  1 => "一",
  2 => "二",
  _ => "其他數字"
};
Code language: Dart (dart)

執行結果

其他數字

注意:此處 switch 屬於運算式,而 getDesc 是箭頭函式;箭頭函式是 Dart 相較其他 C 系列語言獨有的語法。

五、窮舉檢查 Exhaustiveness Checking

若輸入值存在未覆蓋的匹配分支會觸發編譯錯誤,強制開發者補全所有 case;密封類 sealed、列舉 enum 原生支援窮舉檢查,不需額外 _ / default 兜底。

1:可空布林值觸發非窮舉錯誤(可註解執行觀察錯誤訊息)

void main() {
  bool? nullableBool = null;
  // 取消下方程式註解會報編譯錯誤:缺少 null 匹配分支,且無 _ / default 兜底
  /*
  switch (nullableBool) {
    case true:
      print("是");
    case false:
      print("否");
  }
  */
  // 修正方式:新增 null 分支或是底線符 _ 兜底
  switch (nullableBool) {
    case true:
      print("是");
    case false:
      print("否");
    case null:
      print("空值");
  }
}Code language: PHP (php)

執行結果

空值

2:sealed 密封類

代數資料型別,強制開發者完成所有分支窮舉匹配

import 'dart:math' as math;

// 密封類:僅能在同一個檔案內實作子類別
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

程式先驗證型別是否為兩個整數的陣列,符合條件後再透過 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)

輸出:奇數

先判斷輸入是否為整數,接著執行 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)

發佈留言

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