Pattern

一、邏輯或模式 A || B

符合任一子模式即匹配;所有分支必須定義完全相同的變數集合。

enum Color { red, yellow, blue, green }
void main() {
  Color c = Color.red;
  bool primary = switch(c) {
    Color.red || Color.yellow || Color.blue => true,
    _ => false
  };
  print(primary); // true
}Code language: Dart (dart)

二、邏輯與模式 A && B

兩個子模式必須同時匹配;各子模式不可綁定同名變數。

void main() {
  switch((2, 3)) {
    // 編譯錯誤:兩個子模式皆綁定變數b,發生變數名稱衝突
    // case (var a, var b) && (var b, var c): print("ok");
    case (var a, var b) && (>1, <5):
      print("a=$a,b=$b"); // a=2,b=3
  }
}Code language: Dart (dart)

此處 (>1, <5) 代表第一個數字必須大於1、第二個數字必須小於5。

三、關係運算子模式 < > <= >= == !=

用於數值區間判斷,常搭配 && 限定數值範圍

String asciiCharType(int charCode) {
  const space = 32, zero = 48, nine = 57;
  return switch(charCode) {
    < space => "控制字元",
    == space => "空白字元",
    > space && < zero => "標點符號",
    >= zero && <= nine => "數字",
    _ => "其他字元"
  };
}
void main() {
  print(asciiCharType(50)); // 數字
  print(asciiCharType(33)); // 標點符號
}Code language: Dart (dart)

以上範例使用 ASCII 編碼,用來定義控制字元、數字與符號。傳入switch的charCode判斷規則:小於32為控制字元、等於32為空白、介於32至48之間為標點、48到57為數字,其餘歸類為其他。

四、強制轉型模式 sub as Type

解構過程中強制轉換型別,若型別不匹配則執行時拋出例外

void main() {
  (num, Object) rec = (10, "hello");
  var (i as int, s as String) = rec;
  print(i + 5); // 15
  print(s.toUpperCase()); // HELLO
}Code language: Dart (dart)

本範例將rec解構至i與s,若rec第一項非整數、第二項非字串,將觸發執行例外。

以下為錯誤示範:

void main() {
  (num, Object) rec = (9.3, "hello");
  var (i as int, s as String) = rec;
  print(i + 5); // 15
  print(s.toUpperCase()); // HELLO
}Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
type 'double' is not a subtype of type 'int' in type cast
#0      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:3:10)
#1      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

五、空值檢查模式 sub?

僅非空值會匹配,內部變數自動升級為不可空型別;null直接匹配失敗,不會拋出錯誤。

void main() {
  String? str = "test";
  switch(str) {
    case var s?:
      print(s.length); // s為不可空字串,輸出4
    case null:
      print("空值");
  }
}Code language: Dart (dart)

六、空值斷言模式 sub!

僅非空值會匹配;若值為null,直接拋出執行時例外。

void main() {
  List<String?> row = ["user", "bob"];
  switch(row) {
    case ["user", var name!]:
      print(name); // name為不可空字串
  }

  // 用於變數解構
  (int?, int?) pos = (2, 3);
  var (x!, y!) = pos;
  print(x + y);
}Code language: Dart (dart)

var name! 拆解說明

  • var name變數模式var 宣告全新區域變數 name,匹配成功後綁定值;
  • !後置空值斷言模式 — 要求當前值不可為null,若為null則執行階段報錯。

合併含義:var name! 建立新變數name,同時強制斷言該值一定非空。

七、常數模式

字面量、具名常數、const建構子、const集合皆屬常數模式,值相等即匹配。

支援:數字、字串、布林、具名常數、const 物件 / 串列

void main() {
  const target = 10;
  int num = 10;
  switch(num) {
    case 1: print("一");
    case target: print("符合常數10");
    case const [1,2]: print("常數串列");
    default: print("其他");
  }
}Code language: Dart (dart)

執行輸出

符合常數10

八、變數模式 var x / int x / final x

匹配成功後綁定新區域變數;加上型別會同步驗證值的型別。

void main() {
  switch((99, "dart")) {
    case (int a, String b):
      print("$a $b"); // 99 dart
    case (int a, int b):
      print("兩個數值");
  }
}Code language: Dart (dart)

九、識別元模式

依使用場景分三種行為:

  1. 宣告語境 var (a,b):建立新變數
  2. 賦值語境 (a,b) = val:覆蓋既有變數
  3. switch比對語境:視為常數(_ 除外)
void main() {
  const c = 5;
  int val = 2;
  switch(val) {
    case c: print("匹配常數c");
    default: print("無匹配"); // 執行此行
  }
}
Code language: Dart (dart)

十、括號模式 (subPattern)

調整模式運算子優先順序,釐清 ||&& 的執行順序

void main() {
  bool x = true, y = true, z = false;
  bool test = switch(true) {
    (x || y) && z => true,
    _ => false
  };
  print(test); // false
}
Code language: Dart (dart)

十一、串列模式

匹配List物件,依位置解構元素;支援 ... rest運算子擷取任意數量剩餘元素

1. 基礎串列匹配
void main() {
  const a = "a", b = "b";
  var arr = ["a", "b"];
  switch(arr) {
    case [a, b]: print("匹配成功");
    default: print("無匹配");
  }
}Code language: Dart (dart)
2. rest剩餘元素擷取
void main() {
  var [a, b, ...rest, c, d] = [1,2,3,4,5,6,7];
  print("$a $b $rest $c $d"); // 1 2 [3, 4, 5] 6 7
}
Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
1 2 [3, 4, 5] 6 7Code language: CSS (css)

十二、Map模式 {"key": subP}

匹配Map物件,僅驗證指定鍵;目標鍵不存在時拋出 StateError,未提及的多餘鍵直接忽略

void main() {
  var data = {"user": ["Lily", 13]};
  if(data case {"user": [String name, int age]}) {
    print("$name $age"); //Lily 13
  }
}Code language: JavaScript (javascript)

十三、記錄模式

分兩種:位置記錄 (p1,p2)、具名記錄 (k:p1,k2:p2)

支援 :var 簡寫語法,省略重複欄位名稱

void main() {
  // 位置記錄解構
  var (name, age) = ("Doug", 25);
  // 具名欄位簡寫解構
  final (:name, :age) = (name: "Tom", age: 18);
}
Code language: JavaScript (javascript)

十四、物件模式 Class(prop: p)

匹配指定型別物件,解構Getter屬性;支援 :var 簡寫

class Point {
  final int x, y;
  Point(this.x, this.y);
}

void main() {
  Point p = Point(10, 20);
  var Point(:x, :y) = p;
  print("$x $y");
}
Code language: JavaScript (javascript)

十五、萬用字元模式 _

匹配任意值,不綁定變數;用作佔位、僅驗證型別而不取內容

void main() {
  var arr = [1,2,3];
  var [_, mid, _] = arr;
  print(mid); // 2

  switch((10, "abc")) {
    case (int _, String _):
      print("型別匹配成功");
  }
}Code language: JavaScript (javascript)

Pattern

發佈留言

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