SKILL.md
唯讀
名稱
dart-use-pattern-matching
描述
在適當的情境下使用 switch 運算式與模式比對
實作 Dart 模式比對 (Dart Patterns)
目錄
模式選擇策略
根據資料結構與預期結果選擇特定的模式型別。請遵循以下條件指南:
- 若要驗證並從反序列化資料(例如 JSON)中擷取資料: 使用 Map 與 List 模式,同時檢查結構並解構鍵值對 (key-value pairs)。
- 若要處理多個回傳值: 使用 Record 模式將欄位直接解構至區域變數中。
- 若要執行特定型別的行為(代數資料型別 Algebraic Data Types): 將 Object 模式結合
sealed類別使用,以確保涵蓋所有可能情況(窮舉性 exhaustiveness)。 - 若要比對數值範圍或條件: 使用關係 (Relational,
>=、<=) 與邏輯與 (Logical-and,&&) 模式。 - 若多個 case 共享相同邏輯: 使用邏輯或 (Logical-or,
||) 模式來共享單一 case 主體或 Guard 子句。 - 若要忽略特定值: 在集合中使用萬用字元模式 (Wildcard pattern,
_) 或不進行比對的 Rest 元素 (...)。
Switch 敘述 vs. 運算式
根據執行的上下文情境選擇合適的 switch 結構:
- 若要產生數值: 使用 switch 運算式 (switch expression)。
- 語法:
switch (value) { pattern => expression, } - 規則:每個 case 必須是單一運算式。不會隱式貫穿 (no implicit fallthrough)。必須具備窮舉性(涵蓋所有情況)。
- 語法:
- 若要執行敘述或產生副作用: 使用 switch 敘述 (switch statement)。
- 語法:
switch (value) { case pattern: statements; } - 規則:空白的 case 會貫穿 (fall through) 至下一個 case。非空白的 case 則會隱式中斷(不需要使用
break關鍵字)。
- 語法:
核心模式實作
使用以下語法與規則實作模式:
- 邏輯或 (
||):pattern1 || pattern2。兩個分支必須定義完全相同的一組變數。 - 邏輯與 (
&&):pattern1 && pattern2。分支之間不可定義重疊的變數。 - 關係 (Relational):
==、!=、<、>、<=、>=後接常數運算式。 - 型別轉置/轉型 (
as):pattern as Type。若數值不符合該型別則拋出例外。用於在解構過程中強制斷言 (assert) 型別。 - Null 檢查 (
?):pattern?。若數值為 null 則比對失敗。將變數綁定至不可為 null (non-nullable) 的基礎型別。 - Null 斷言 (
!):pattern!。若數值為 null 則拋出例外。 - 變數 (Variable):
var name或Type name。將比對成功的數值綁定至新的區域變數。 - 萬用字元 (
_): 比對任意數值並予以丟棄。 - List:
[pattern1, pattern2]。比對長度完全符合的列表,除非使用了 Rest 元素(...或...var rest)。 - Map:
{"key": pattern}。比對包含指定鍵 (key) 的 Map。忽略未比對的鍵。 - Record:
(pattern1, named: pattern2)。比對結構完全相同的 Record。使用:var name可自動推導 getter 的名稱。 - Object:
ClassName(field: pattern)。比對ClassName的實例。使用:var field可自動推導 getter 的名稱。
工作流程
任務進度:實作模式比對
在實作複雜的模式比對邏輯時,可複製此檢查清單來追蹤進度:
- [ ] 確定正在評估的資料結構(JSON、Record、Class、Enum)。
- [ ] 選擇合適的 switch 結構(計算數值用運算式 Expression,副作用用敘述 Statement)。
- [ ] 定義所需的模式(Object、Map、List、Record)。
- [ ] 使用變數模式 (
var x、:var y) 擷取所需的資料。 - [ ] 針對無法透過模式表達的邏輯,套用 Guard 子句 (
when condition)。 - [ ] 使用萬用字元 (
_) 或default子句處理未比對的情況(若未使用 sealed 類別)。 - [ ] 執行窮舉性 (exhaustiveness) 驗證器。
回饋循環:窮舉性檢查
當對 sealed 類別或 enum 進行 switch 比對時,必須確保所有子型別都已處理。
- 執行驗證器: 執行
dart analyze。 - 檢視錯誤: 尋找「The type 'X' is not exhaustively matched by the switch cases」相關錯誤訊息。
- 修正問題: 為未處理的子型別補上缺失的 Object 模式,或者若允許預設退回機制,可新增萬用字元 (
_) case。
範例
JSON 驗證與解構
使用 Map 與 List 模式在單一步驟中完成結構驗證與資料擷取。
輸入:
var data = {
'user': ['Lily', 13],
};
實作:
if (data case {'user': [String name, int age]}) {
print('User $name is $age years old.');
} else {
print('Invalid JSON structure.');
}
代數資料型別(Sealed 類別)
將 Object 模式搭配 switch 運算式使用,以窮舉方式處理型別家族。
實作:
sealed class Shape {}
class Square implements Shape {
final double length;
Square(this.length);
}
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
// 由於 `sealed` 修飾詞,switch 運算式能保證涵蓋所有情況(窮舉性)。
double calculateArea(Shape shape) => switch (shape) {
Square(length: var l) => l * l,
Circle(:var radius) => math.pi * radius * radius,
};
變數對調與解構
使用變數賦值模式來對調數值,或在不使用暫存變數的情況下擷取 Record 欄位。
實作:
var (a, b) = ('left', 'right');
(b, a) = (a, b); // 對調數值
// 解構函式回傳值
var (name, age) = getUserInfo();
Guard 子句與邏輯或
在模式比對成功後,使用 when 來評估自訂條件。
實作:
switch (shape) {
case Square(size: var s) || Circle(size: var s) when s > 0:
print('Valid symmetric shape with size $s');
case Square() || Circle():
print('Invalid or empty shape');
default:
print('Unknown shape');
}






