SKILL.md
只读
名称
dart-use-pattern-matching
描述
在合适场景下使用 switch 表达式与模式匹配(pattern matching)。
Dart 模式匹配实现指南
目录
模式选择策略
根据数据结构与目标需求,灵活选择具体的模式类型。请遵循以下条件准则:
- 校验并提取反序列化数据(如 JSON): 使用 Map 和 List 模式,在检查结构的同时完成键值解构。
- 处理多返回值: 使用 Record 模式将字段直接解构到局部变量中。
- 执行特定类型的行为(代数数据类型 ADT): 使用 Object 模式配合
sealed类,确保分支穷尽性(exhaustiveness)。 - 匹配数值范围或条件: 使用关系运算符(
>=、<=)与逻辑与(&&)模式。 - 多个 case 共享逻辑: 使用逻辑或(
||)模式共享同一个 case 主体或 Guard 条件子句(guard clause)。 - 忽略特定值: 使用通配符模式(
_)或集合中的 Rest 元素(...)忽略不关心的项。
Switch 语句 vs. 表达式
根据执行上下文选择合适的 switch 结构:
- 需要计算或返回值时: 使用 switch 表达式。
- 语法:
switch (value) { pattern => expression, } - 规则:每个 case 必须是单条表达式。无隐式贯穿(fallthrough)。必须具备穷尽性。
- 语法:
- 需要执行语句或副作用时: 使用 switch 语句。
- 语法:
switch (value) { case pattern: statements; } - 规则:空 case 会贯穿到下一个 case;非空 case 会隐式 break(无需显式写
break关键字)。
- 语法:
核心模式实现
按照以下语法与规则实现各种模式:
- 逻辑或(
||):pattern1 || pattern2。两个分支定义的变量集合必须完全一致。 - 逻辑与(
&&):pattern1 && pattern2。两个分支不能定义重叠的变量。 - 关系模式(Relational):
==、!=、<、>、<=、>=后接常量表达式。 - 类型转换(
as):pattern as Type。如果值与类型不匹配则抛出异常。用于解构过程中强制断言类型。 - Null 校验(
?):pattern?。如果值为 null 则匹配失败;匹配成功时将变量绑定为非空基类型。 - Null 断言(
!):pattern!。如果值为 null 则直接抛出异常。 - 变量模式(Variable):
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)。 - [ ] 对无法通过单纯模式表达的逻辑添加 Guard 条件子句(
when condition)。 - [ ] 使用通配符(
_)或default分支处理未匹配的情况(若未声明 sealed 类)。 - [ ] 运行穷尽性校验工具。
反馈循环:穷尽性检查(Exhaustiveness Checking)
当对 sealed 类或枚举使用 switch 时,必须确保覆盖了所有子类型。
- 运行校验器: 执行
dart analyze。 - 排查错误: 查找形如
"The type 'X' is not exhaustively matched by the switch cases"的错误。 - 修复方案: 补齐缺失子类型的 Object 模式,或者在允许默认兜底时添加通配符(
_)分支。
代码示例
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 类)
配合 switch 表达式与 Object 模式,对类型族进行穷尽性处理。
实现:
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');
}






