Pattern 模式匹配

Dart 语言版本 ≥ 3.0,才可以使用Patterns

一、Pattern 核心作用

Pattern 是 Dart 独立语法类别(和语句、表达式同级),描述一组值的结构形态,两大核心能力:匹配(Match)解构(Destructure),可同时使用。

  1. 匹配 Match:校验值是否符合预期形态
    • 是否是指定常量
    • 是否匹配特定类型
    • 是否拥有指定结构(List/Map/ 对象 / 记录)
    • 是否满足条件
  2. 解构 Destructure:匹配成功后,快速提取值内部字段、元素,绑定到变量

1. 常量匹配示例

void main() {
	int number = 1;
	switch (number) {
	  case 1:
		print('one'); // 常量模式匹配 number == 1
	  default:
		print('other');
	}
}Code language: Dart (dart)

执行结果

one

2. 递归子模式匹配

模式支持嵌套子模式,逐层校验内部结构

void main() {
  const a = 'a';
  const b = 'b';
  var obj = ['a', 'b'];
  switch (obj) {
    case [a, b]:
      print('$a, $b');
    default:
      print('不匹配');
  }
}Code language: Dart (dart)

执行结果

a, b

3. 解构基础示例

var numList = [1, 2, 3];
// List模式解构列表元素,绑定新变量
var [x, y, z] = numList; 
print(x + y + z); // 6 x :1 y:2 z:3Code language: PHP (php)

4. 嵌套模式匹配 + 解构

void main() {
  var list = ['b', 99];
  switch (list) {
    // 逻辑或模式:首元素为a或b,第二个绑定变量c
    case ['a' || 'b', var c]:
      print(c); // 99
  }
}Code language: Dart (dart)

二、Pattern 常用例子

1. 局部变量声明

用于解构赋值,一次性创建多个变量

// 记录+列表嵌套模式解构
var (str, [n1, n2]) = ('text', [10, 20]);
print(str); //text
print(n1 + n2); //30Code language: Dart (dart)

2. 变量赋值(给已有变量重新赋值,无需临时变量交换)

var (a, b) = ("左", "右");
(b, a) = (a, b); // 交换两个变量
print('$a $b'); // 右 左Code language: Dart (dart)

3. switch /if-case 分支(最常用,带守卫 when)

case 内全部是可反驳模式(匹配成功进入分支,失败走下一条)

基础多类型 case

void testSwitch(dynamic obj) {
  switch (obj) {
    case 1:
      print('数字1');
    case >= 10 && <= 20:
      print('10~20区间数字');
    case (var a, var b):
      print('记录:$a,$b');
    default:
      print('无匹配');
  }
}Code language: Dart (dart)

逻辑或模式:多分支共用逻辑

enum Color { red, yellow, blue, green }
void main() {
  Color color = Color.red;
  bool isPrimary = switch (color) {
    Color.red || Color.yellow || Color.blue => true,
    _ => false,
  };
  print(isPrimary); // true
}
Code language: PHP (php)

when 守卫子句(匹配后再增加一个额外条件过滤)

sealed class Shape {}
class Square { final double size; Square(this.size); }
class Circle { final double size; Circle(this.size); }

void checkShape(Shape shape) {
  switch (shape) {
    // Square、Circle共用匹配逻辑,增加size>0条件
    case Square(size: var s) || Circle(size: var s) when s > 0:
      print('有效对称图形');
    default:
      print('无效图形');
  }
}Code language: Dart (dart)

when 对比普通 if 区别

void compareWhen((int, int) pair) {
  switch (pair) {
    case (int a, int b):
      if (a > b) print('前者更大');
      // if条件不成立:直接结束整个switch,不会走后面case
    case (int a, int b) when a > b:
      print('【when守卫】前者更大');
      // when不成立:仅跳过当前case,继续匹配下一个case
    case (int a, int b):
      print('前者更小或相等');
  }
}

void main() {
  print("===== 测试 (5, 2) a > b =====");
  compareWhen((5, 2));

  print("\n===== 测试 (2, 5) a < b =====");
  compareWhen((2, 5));
}Code language: Dart (dart)

4. for /for-in 循环(解构 MapEntry 最实用)


void main() {
	Map<String, int> hist = {'a': 23, 'b': 100};
	
	// 完整写法
	for (var MapEntry(key: key, value: count) in hist.entries) {
	  print('$key$count');
	}
	
	// 简写语法:key:key 简化为 :key
	for (var MapEntry(:key, value: count) in hist.entries) {
	  print('$key$count');
	}
}Code language: Dart (dart)

执行结果

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
a:23
b:100
a:23
b:100
Code language: CSS (css)

三、Pattern 典型业务使用场景

1:函数多返回值(Record 记录解构)

传统写法(繁琐)

(String, int) userInfo() => ("Lily", 13);
void main() {
  var info = userInfo();
  var name = info.$1;
  var age = info.$2;
}
Code language: Dart (dart)

模式解构简写

var (name, age) = userInfo();
// 具名字段记录解构
final (:name, :age) = getData(); // 返回 (name: "Doug", age:25)Code language: Dart (dart)

具体例子


(String, int) userInfo() => ("Lily", 18);


({String name, int age}) getData() => (name: "Doug", age: 25);

void main() {
  {
    var (name, age) = userInfo();
    print("姓名:$name,年龄:$age");
  }

  // 内部 name/age 和上面互不干扰
  {
    final (:name, :age) = getData();
    print("姓名:$name,年龄:$age");
  }
}Code language: Dart (dart)

2:Class 类实例解构(对象模式)

class Foo {
  final String one;
  final int two;
  Foo({required this.one, required this.two});
}

void main() {
  final Foo myFoo = Foo(one: "test", two: 66);
  var Foo(:one, :two) = myFoo;
  print('$one $two'); //test 66
}Code language: Dart (dart)

3:代数数据类型(密封类 + switch 分支计算)

统一处理一组关联子类,不用分散写实例方法

import 'dart:math';

sealed class Shape {}
class Square implements Shape { final double length; Square(this.length); }
class Circle implements Shape { final double radius; Circle(this.radius); }

double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(radius: var r) => pi * r * r,
};
Code language: Dart (dart)

具体例子

import 'dart:math';

// 密封父类,限制只能在当前文件实现子类
sealed class Shape {}

// 正方形子类
class Square implements Shape {
  final double length;
  Square(this.length);
}

// 圆形子类
class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

// 使用 switch 表达式 + 对象模式匹配,统一计算面积
double calculateArea(Shape shape) => switch (shape) {
  // 匹配 Square,解构取出 length 赋值给变量 l
  Square(length: var l) => l * l,
  // 匹配 Circle,解构取出 radius 赋值给变量 r
  Circle(radius: var r) => pi * r * r,
};

void main() {
  // 创建图形实例
  Shape square = Square(5);
  Shape circle = Circle(3);

  // 调用计算面积
  double squareArea = calculateArea(square);
  double circleArea = calculateArea(circle);

  print("正方形面积:$squareArea");    // 25.0
  print("圆形面积:${circleArea.toStringAsFixed(2)}"); // 28.27
}Code language: Dart (dart)

运行结果

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
正方形面积:25.0
圆形面积:28.27Code language: CSS (css)

4:JSON 数据校验与解构(大幅简化多层判断)

(不使用模式的情况下):多层嵌套类型判断,代码冗长

void oldCheck(Map data) {
  if (data is Map<String, Object?> && data.containsKey('user')) {
    var user = data['user'];
    if (user is List && user.length == 2) {
      String name = user[0] as String;
      int age = user[1] as int;
      print('$name $age');
    }
  }
}Code language: Dart (dart)

if-case 模式:一行完成结构校验 + 类型校验 + 变量绑定

void newCheck(Map data) {
  if (data case {'user': [String name, int age]}) {
    print('用户 $name,年龄 $age');
  }
}Code language: Dart (dart)

该模式同时校验:

  1. data 是 Map、非空
  2. 包含 user 键
  3. user 对应长度为 2 的列表
  4. 列表第一个是 String、第二个是 int
  5. 自动绑定 name、age 局部变量

具体使用例子

void main() {
  // 1. 合法JSON结构:匹配成功
  final validJson = {
    'user': ['Lily', 13]
  };
  newCheck(validJson); // 输出:用户 Lily,年龄 13

  // 2. user内类型不匹配:字符串年龄,匹配失败 因为16是字符串
  final wrongTypeJson = {
    'user': ['Tom', '16']
  };
  newCheck(wrongTypeJson); // 无输出

  // 3. user数组长度不足:匹配失败 没有年龄
  final shortJson = {
    'user': ['Jack']
  };
  newCheck(shortJson); // 无输出

  // 4. 缺少user键:匹配失败
  final noUserJson = {
    'info': ['Bob', 20]
  };
  newCheck(noUserJson); // 无输出
}

// 使用 if-case Map+List 模式一次性校验结构、类型、解构赋值
void newCheck(Map data) {
  if (data case {'user': [String name, int age]}) {
    print('用户 $name,年龄 $age');
  } else {
    print('数据格式不合法');
  }
}Code language: PHP (php)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注