SKILL.md
readonlyread-only
name
dart-use-pattern-matching
description
在適當情況下使用 switch 表達式與模式匹配
實作 Dart 模式
目錄
模式選擇策略
根據資料結構與預期結果套用特定模式類型。請遵循以下條件指引:
- 若要驗證並從反序列化資料(例如 JSON)中提取: 使用 Map 與 List 模式同時檢查結構並解構鍵值對。
- 若要處理多個回傳值: 使用 Record 模式將欄位直接解構為區域變數。
- 若要執行型別特定的行為(代數資料類型): 使用 Object 模式搭配
sealed類別以確保窮舉性。 - 若要比對數值範圍或條件: 使用關係模式(
>=,<=)與邏輯且(&&)模式。 - 若多個 case 共用邏輯: 使用邏輯或(
||)模式共用單一 case 主體或守衛子句。 - 若要忽略特定值: 在集合中使用萬用字元模式(
_)或不匹配的 Rest 元素(...)。
Switch 陳述式 vs. 表達式
根據執行上下文選擇適當的 switch 結構:
- 若要產生值: 使用 switch 表達式。
- 語法:
switch (value) { pattern => expression, } - 規則:每個 case 必須是單一表達式。無隱含貫穿。必須窮舉。
- 語法:
- 若要執行陳述式或副作用: 使用 switch 陳述式。
- 語法:
switch (value) { case pattern: statements; } - 規則:空的 case 會貫穿到下一個 case。非空的 case 會隱含 break(不需要
break關鍵字)。
- 語法:
核心模式實作
使用以下語法與規則實作模式:
- 邏輯或(
||):pattern1 || pattern2。兩個分支必須定義完全相同的變數集合。 - 邏輯且(
&&):pattern1 && pattern2。分支不得定義重疊的變數。 - 關係:
==,!=,<,>,<=,>=後接常數表達式。 - 轉型(
as):pattern as Type。若值不符合型別則拋出例外。用於在解構時強制斷言型別。 - 空值檢查(
?):pattern?。若值為 null 則匹配失敗。將變數繫結至非可空基底型別。 - 空值斷言(
!):pattern!。若值為 null 則拋出例外。 - 變數:
var name或Type name。將匹配的值繫結至新的區域變數。 - 萬用字元(
_): 匹配任何值並將其丟棄。 - List:
[pattern1, pattern2]。匹配精確長度的列表,除非使用 Rest 元素(...或...var rest)。 - Map:
{"key": pattern}。匹配包含指定鍵的 Map。忽略未匹配的鍵。 - Record:
(pattern1, named: pattern2)。匹配精確形狀的 Record。使用:var name推斷 getter 名稱。 - Object:
ClassName(field: pattern)。匹配ClassName的實例。使用:var field推斷 getter 名稱。
工作流程
任務進度:實作模式匹配
複製此檢查清單以追蹤實作複雜模式匹配邏輯的進度:
- [ ] 識別正在評估的資料結構(JSON、Record、Class、Enum)。
- [ ] 選擇適當的 switch 結構(表達式用於值,陳述式用於副作用)。
- [ ] 定義所需的模式(Object、Map、List、Record)。
- [ ] 使用變數模式(
var x,:var y)提取所需資料。 - [ ] 對無法透過模式表達的邏輯套用守衛子句(
when condition)。 - [ ] 使用萬用字元(
_)或default子句處理未匹配的 case(若未使用 sealed 類別)。 - [ ] 執行窮舉性驗證器。
回饋迴圈:窮舉性檢查
當對 sealed 類別或列舉進行 switch 時,必須確保所有子型別都已處理。
- 執行驗證器: 執行
dart analyze。 - 檢視錯誤: 尋找「型別 'X' 未被 switch case 窮舉匹配」的錯誤。
- 修正: 為未處理的子型別新增缺少的 Object 模式,或者若可接受預設回退則新增萬用字元(
_)case。
範例
JSON 驗證與解構
使用 Map 與 List 模式在單一步驟中驗證結構並提取資料。
輸入:
var data = {
'user': ['Lily', 13],
};
實作:
if (data case {'user': [String name, int age]}) {
print('使用者 $name 今年 $age 歲。');
} else {
print('無效的 JSON 結構。');
}
代數資料類型(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);
}
// switch 表達式因 `sealed` 修飾詞保證窮舉性。
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();
守衛子句與邏輯或
在模式匹配後使用 when 評估任意條件。
實作:
switch (shape) {
case Square(size: var s) || Circle(size: var s) when s > 0:
print('有效的對稱形狀,大小為 $s');
case Square() || Circle():
print('無效或空的形狀');
default:
print('未知形狀');
}






