模式

Dart 3.0引入了一个非常强大的功能,模式(Pattern)。一般来说,依据模式的形状及其上下文, 模式可以匹配(match)解构(destructure)一个值,匹配与解构可同时进行。

匹配

模式匹配可以检查一个值是否:

  • 具有特定的形状;
  • 是特定常数;
  • 等于某个值;
  • 有特定的数据类型。

这么说还是有点抽象,我们来看下面的示例。

//ch0301_1.dart
void main() {
  const numbers = [1, 2, 3]; // 1

  if (numbers case [_, _, _]) { // 2
    print('numbers is a list which has 3 elements.');
  }

  if (numbers case [1, 2, 3]) { // 3
    print('numbers is exactly [1, 2, 3].');
  }

  const point = (x: 3, y: 4); // 4
  
  if (point case (x: _, y: _)) { // 5
    print("point is a record with named fields x and y.");
  }
}

  1. 声明了一个const列表numbers;
  2. 检查numbers是否是一个具有2个元素的列表;
  3. 检查numbers是否就等于 [1, 2, 3];
  4. 声明一个记录point;
  5. 检查point是否是一个具有命名字段 xy 的记录(record)。

解构

模式解构提供了一种便捷的声明式语法,可以将一个值分解成各部件(parts),并将部分或全部的部件,绑定至局部变量。

//ch0301_2.dart
void main() {
  const numbers = [1, 2, 3]; 

  if (numbers case [var a, var b, _]) { // 1
    print('a=$a b=$b'); 
  }

  if (numbers case [var a, ...var rest]) { // 2
    print('The first element is $a, and the rest is $rest'); 
  }

  const point = (x: 3, y: 4); 

  if (point case (x: var a, :var y)) { // 3
    print("a=$a y=$y");
  }
}
  1. 匹配numbers并绑定前2个元素至变量ab;
  2. 匹配numbers并绑定第1元素至变量a,绑定剩余的元素至变量rest,注意var rest之前有3个点(....);
  3. 匹配point,并将其x字段绑定至变量ay字段绑定至变量y;这里的:var yy:var y的简便写法。

下面是与类相关的模式匹配的一个示例:

// ch0301_3.dart
void main() {
  const point = Point(3, 4); // 4
  if (point case Point(:var x, :var y, :var z)) { // 5
    print("x=$x, y=$y, z=$z"); 
  }
}

class Point { 
  const Point(this.x, this.y); // 1

  final int x; // 2
  final int y; // 2a
  int get z => x + y; // 3
}
  1. 这是类Point的构造函数;
  2. x yPoint 的两个公开的字段;
  3. z 是 getter 方法,由xy计算而成,形式上当成字段来用;
  4. 声明一个变量point,它Point类的一个实例;
  5. 解构point,并将其部件分别绑定值变量 xyz

解构不但可以绑定字段,还可以绑定函数/方法(在类中定义的函数),也就是为什么在描述解构时,采用了部件(而非字段)这个词。

// ch0301_4.dart
void main() {
  const rect = Rectangle(5, 6);
  if (rect case Rectangle(:var area)) {
    print("${area(.1)} m²");
  }
}

class Rectangle {
  const Rectangle(this.a, this.b);

  final double a;
  final double b;

  double area([double unit = 1]) => a * b * unit * unit;
}

参考资料