Dart 3 引入了强大的 模式匹配(Pattern Matching) 特性,通过解构模式(Destructuring Patterns),开发者可以更简洁地处理复杂数据结构,如列表、映射、记录和对象。模式匹配不仅提升代码可读性,还在变量声明、switch 表达式和 if-case 等场景中大放异彩。本章深入探讨 列表模式、映射模式、记录模式 和 对象模式,通过实战案例展示其应用,帮助你掌握 Dart 3 的现代编程范式。
3.1 列表模式 (List Pattern)
列表模式允许解构 List 数据结构,提取元素或嵌套内容,结合剩余元素模式(...)实现灵活匹配。
3.1.1 基本语法和解构元素
列表模式使用方括号 [],通过位置解构 List 元素。
void main() {
const point = [1, 2];
final [x, y] = point; // 解构为变量 x 和 y
print('x: $x, y: $y'); // 输出: x: 1, y: 2
}
- 语法:
[pattern1, pattern2]匹配列表的对应位置。 - 要求:列表长度必须匹配模式长度,否则抛出异常。
3.1.2 嵌套列表的解构
列表模式支持嵌套解构,处理多维列表。
void main() {
const matrix = [[1, 2], [3, 4]];
final [[a, b], [c, d]] = matrix;
print('a: $a, b: $b, c: $c, d: $d'); // 输出: a: 1, b: 2, c: 3, d: 4
}
- 场景:常用于解析 JSON 或多维数据。
3.1.3 ... 剩余元素模式(Rest Pattern)
... 捕获剩余元素,类似 JavaScript 的 Spread Operator。
void main() {
const numbers = [1, 2, 3, 4, 5];
final [first, second, ...rest] = numbers;
print('first: $first, second: $second, rest: $rest'); // 输出: first: 1, second: 2, rest: [3, 4, 5]
}
- 灵活性:
...rest可出现在模式开头、中间或结尾。 - 限制:一个模式中只能有一个
...。
3.1.4 在不同上下文中的应用
列表模式在多种场景中简化代码:
- 变量声明:
const coords = [10, 20]; var [x, y] = coords; // 解构赋值 switch表达式:String describePoint(List<int> point) => switch (point) { [0, 0] => 'Origin', [int x, 0] => 'On x-axis at $x', [0, int y] => 'On y-axis at $y', [int x, int y] => 'At ($x, $y)', _ => 'Unknown' }; void main() { print(describePoint([0, 0])); // 输出: Origin print(describePoint([5, 0])); // 输出: On x-axis at 5 }if-case:void checkPoint(List<int> point) { if (point case [int x, int y] when x > 0 && y > 0) { print('Positive quadrant: ($x, $y)'); } else { print('Not in positive quadrant'); } } void main() { checkPoint([1, 2]); // 输出: Positive quadrant: (1, 2) checkPoint([-1, 2]); // 输出: Not in positive quadrant }
生产建议:在 switch 中使用 when 子句添加条件,增强匹配逻辑;优先使用 if-case 代替嵌套 if。
3.2 映射模式 (Map Pattern)
映射模式解构 Map 数据,匹配键值对,适合处理 JSON 或键值数据。
3.2.1 基本语法和解构键值对
映射模式使用大括号 {},指定键和值的模式。
void main() {
const user = {'name': 'Alice', 'age': 30};
final {'name': String name, 'age': int age} = user;
print('Name: $name, Age: $age'); // 输出: Name: Alice, Age: 30
}
- 语法:
{'key': pattern}匹配指定键。 - 类型检查:模式可指定类型(如
String、int)。
3.2.2 解构特定键
可以只解构部分键,未匹配的键被忽略。
void main() {
const user = {'name': 'Bob', 'age': 25, 'email': 'bob@example.com'};
final {'name': name} = user;
print('Name: $name'); // 输出: Name: Bob
}
- 场景:从复杂 JSON 中提取特定字段。
3.2.3 ... 剩余元素模式(Rest Pattern)
... 捕获未匹配的键值对。
void main() {
const user = {'name': 'Charlie', 'age': 35, 'email': 'charlie@example.com'};
final {'name': name, ...rest} = user;
print('Name: $name, Rest: $rest'); // 输出: Name: Charlie, Rest: {age: 35, email: charlie@example.com}
}
3.2.4 在不同上下文中的应用
映射模式在以下场景中简化逻辑:
- 变量声明:
const config = {'host': 'localhost', 'port': 8080}; var {'host': host, 'port': port} = config; switch表达式:String parseUser(Map<String, dynamic> user) => switch (user) { {'name': 'Admin', 'role': String role} => 'Admin with role: $role', {'name': String name, 'age': >= 18} => 'Adult: $name', _ => 'Unknown user' }; void main() { print(parseUser({'name': 'Admin', 'role': 'superuser'})); // 输出: Admin with role: superuser print(parseUser({'name': 'Alice', 'age': 20})); // 输出: Adult: Alice }if-case:void checkUser(Map<String, dynamic> user) { if (user case {'name': String name, 'age': >= 18}) { print('$name is an adult'); } else { print('Not an adult or invalid user'); } } void main() { checkUser({'name': 'Bob', 'age': 25}); // 输出: Bob is an adult }
生产建议:使用映射模式解析 API 响应,确保键存在(结合 when 子句校验)。
3.3 记录模式 (Record Pattern)
记录(Records)是 Dart 3 引入的不可变数据结构,记录模式用于解构记录。
3.3.1 记录(Records)作为数据类型简介
记录是轻量级、匿名的复合数据类型,支持位置字段和命名字段。
void main() {
const point = (x: 1, y: 2); // 命名记录
const pair = (3, 4); // 位置记录
print(point); // 输出: (x: 1, y: 2)
print(pair); // 输出: (3, 4)
}
3.3.2 位置记录和命名记录的解构
- 位置记录:
void main() { const pair = (1, 2); final (a, b) = pair; print('a: $a, b: $b'); // 输出: a: 1, b: 2 } - 命名记录:
void main() { const point = (x: 3, y: 4); final (x: x, y: y) = point; print('x: $x, y: $y'); // 输出: x: 3, y: 4 }
3.3.3 混合解构(部分解构)
可以解构部分字段,忽略其他字段。
void main() {
const data = (id: 1, name: 'Alice', age: 30);
final (id: id, name: name) = data;
print('ID: $id, Name: $name'); // 输出: ID: 1, Name: Alice
}
3.3.4 在不同上下文中的应用
记录模式在函数返回多值时特别有用:
- 变量声明:
(int, String) getUser() => (1, 'Alice'); final (id, name) = getUser(); switch表达式:String describeRecord((int, String) record) => switch (record) { (0, _) => 'Zero ID', (int id, String name) => 'ID: $id, Name: $name', }; void main() { print(describeRecord((1, 'Bob'))); // 输出: ID: 1, Name: Bob }if-case:void checkRecord((int, String) record) { if (record case (int id, String name) when id > 0) { print('Valid user: $name'); } } void main() { checkRecord((1, 'Charlie')); // 输出: Valid user: Charlie }
生产建议:记录适合函数返回多值(如 (status, data)),用记录模式解构提高代码清晰度。
3.4 对象模式 (Object Pattern)
对象模式解构类实例的属性或 getter,结合类型检查实现精确匹配。
3.4.1 基本语法和解构对象属性
对象模式匹配类的属性或 getter。
class User {
final String name;
final int age;
User(this.name, this.age);
}
void main() {
const user = User('Alice', 30);
final User(name: name, age: age) = user;
print('Name: $name, Age: $age'); // 输出: Name: Alice, Age: 30
}
3.4.2 getter 方法的匹配
可以匹配 getter 方法。
class User {
final String _name;
final int _age;
User(this._name, this._age);
String get name => _name;
int get age => _age;
}
void main() {
const user = User('Bob', 25);
final User(name: name, age: age) = user;
print('Name: $name, Age: $age'); // 输出: Name: Bob, Age: 25
}
3.4.3 级联模式(..)与模式匹配的结合
Dart 的级联运算符(..)可与对象模式结合,简化操作。
class User {
String name;
int age;
User(this.name, this.age);
}
void main() {
final user = User('Charlie', 35);
if (user case User(name: var name, age: var age)) {
user..name = 'Updated $name'..age = age + 1;
print('Updated: ${user.name}, ${user.age}'); // 输出: Updated: Updated Charlie, 36
}
}
3.4.4 在不同上下文中的应用
对象模式在复杂类型匹配中非常强大:
- 变量声明:
final user = User('Dave', 40); var User(name: name) = user; // 只解构 name switch表达式:String describeUser(User user) => switch (user) { User(name: 'Admin') => 'Administrator', User(age: >= 18) => 'Adult user', User(name: String name) => 'User: $name', }; void main() { print(describeUser(User('Admin', 50))); // 输出: Administrator print(describeUser(User('Eve', 20))); // 输出: Adult user }if-case:void checkUser(User user) { if (user case User(age: >= 18)) { print('Adult user'); } else { print('Not an adult'); } } void main() { checkUser(User('Frank', 16)); // 输出: Not an adult }
生产建议:对象模式适合处理复杂类实例,结合 when 子句校验属性值。
小结
Dart 3 的解构模式(列表、映射、记录、对象)极大提升了代码的简洁性和表达力:
- 列表模式:解构数组,结合
...捕获剩余元素,适合处理序列数据。 - 映射模式:提取键值对,解析 JSON 或配置数据。
- 记录模式:处理轻量级多值返回,简化函数返回值解构。
- 对象模式:匹配类属性或 getter,适合复杂类型处理。
通过变量声明、switch 和 if-case,这些模式在多种场景中简化逻辑。建议在生产环境中:
- 使用类型注解(如
String、int)增强模式安全性。 - 结合
when子句添加条件校验。 - 优先使用记录模式处理多值返回。