模式类型

Last updated: ... / Reads: 41 Edit

本页是不同类型模式的参考。 有关模式工作原理的概述、在 Dart 中的使用位置以及常见模式 用例,请访问主模式页面。

模式优先级

与运算符优先级类似, 模式评估遵循优先规则。 您可以使用括号中的模式来执行以下操作 首先评估低优先级模式。

本文档按优先级升序列出了模式类型:

逻辑模式的优先级低于逻辑模式, 逻辑和模式的优先级低于关系模式, 等等。

后修复一元模式(强制转换、null-check、 和 null-assert) 共享相同的优先级。

其余主要模式具有最高优先级。 集合类型(记录、列表和映射) 和对象模式包含其他 数据,因此首先作为外部模式进行评估。

逻辑-或

subpattern1 || subpattern2

逻辑或模式通过以下任何一种方式分隔子模式并匹配 分支匹配。分支从左到右计算。一旦分支匹配,, 其余的不进行评估。||

var isPrimary = switch (color) {
  Color.red || Color.yellow || Color.blue => true,
  _ => false
};

逻辑模式中的子模式可以绑定变量,但分支必须 定义同一组变量,因为当 模式匹配。

逻辑和

subpattern1 && subpattern2

仅当两个子模式都匹配时,由匹配分隔的一对模式。如果 左分支不匹配,不计算右分支。&&

逻辑和模式中的子模式可以绑定变量,但 每个子模式不得重叠,因为如果模式,它们都将被绑定 比赛:

switch ((1, 2)) {
  // Error, both subpatterns attempt to bind 'b'.
  case (var a, var b) && (var b, var c): // ...
}

关系

== expression

< expression

关系模式使用以下任何一项将匹配值与给定常量进行比较 相等运算符或关系运算符:、、、、、和。==!=<><=>=

在对匹配值调用相应的运算符时,模式匹配 以常量作为参数返回。true

关系模式对于数字范围的匹配非常有用,尤其是在 结合逻辑和模式:

String asciiCharType(int char) {
  const space = 32;
  const zero = 48;
  const nine = 57;

  return switch (char) {
    < space => 'control',
    == space => 'space',
    > space && < zero => 'punctuation',
    >= zero && <= nine => 'digit',
    _ => ''
  };
}

Cast

foo as String

转换模式允许您在将值传递给另一个子模式之前在解构过程中插入类型转换:

(num, Object) record = (1, 's');
var (i as int, s as String) = record;

如果值没有指定的类型,则转换模式将抛出异常。与空断言模式一样,这使您可以强制断言某些解构值的预期类型。

空检查

subpattern?

如果值不为空,则空检查模式首先匹配,然后将内部模式与相同的值进行匹配。它们允许您绑定一个变量,该变量的类型是所匹配的可为空值的不可为空基类型。

要将值视为匹配失败而不抛出异常,请使用空检查模式。 null

String? maybeString = 'nullable with base type String';
switch (maybeString) {
  case var s?:
  // 's' has type non-nullable String here.
}

要在值为 null 时进行匹配,请使用常量 pattern 。 null

空断言

subpattern!

如果对象不为空,则空断言模式首先匹配,然后匹配值。它们允许非空值流过,但如果匹配的值为空则抛出异常。

为了确保值不会被默默地视为匹配失败,请在匹配时使用空断言模式: null

List<String?> row = ['user', null];
switch (row) {
  case ['user', var name!]: // ...
  // 'name' is a non-nullable string here.
}

要从变量声明模式中消除值,请使用空断言模式: null

(int?, int?) position = (2, 3);

var (x!, y!) = position;

要在值为 null 时进行匹配,请使用常量 pattern 。 null

持续的

123, null, 'string', math.pi, SomeClass.constant, const Thing(1, 2), const (1 + 2)

当值等于常量时常量模式匹配:

switch (number) {
  // Matches if 1 == number.
  case 1: // ...
}

您可以直接使用简单的文字和对命名常量的引用作为常量模式:

  • 数字文字 (, 123 45.56 )
  • 布尔文字 ( true )
  • 字符串文字 ( 'string' )
  • 命名常量 (, , someConstant math.pi double.infinity )
  • 常量构造函数 ( const Point(0, 0) )
  • 常量集合文字 (, const [] const {1, 2} )

更复杂的常量表达式必须加括号并以 () 为前缀: const const (1 + 2)

// List or map pattern:
case [a, b]: // ...

// List or map literal:
case const [a, b]: // ...

多变的

var bar, String str, final int _

变量模式将新变量绑定到已匹配或解构的值。它们通常作为解构模式的一部分出现,以捕获解构值。

这些变量位于仅当模式匹配时才可访问的代码区域的范围内。

switch ((1, 2)) {
  // 'var a' and 'var b' are variable patterns that bind to 1 and 2, respectively.
  case (var a, var b): // ...
  // 'a' and 'b' are in scope in the case body.
}

类型化变量模式仅在匹配值具有声明的类型时才匹配,否则失败:

switch ((1, 2)) {
  // Does not match.
  case (int a, String b): // ...
}

您可以使用通配符模式作为变量模式。

标识符

foo, _

标识符模式的行为可能类似于常量模式或变量模式,具体取决于它们出现的上下文:

  • 声明上下文:声明一个新变量,其标识符名称为: var (a, b) = (1, 2);
  • 赋值上下文:分配给具有标识符名称的现有变量: (a, b) = (3, 4);
  • 匹配上下文:视为命名常量模式(除非其名称为 ): _
const c = 1;
switch (2) {
  case c:
    print('match $c');
  default:
    print('no match'); // Prints "no match".
}
  • 任何上下文中的通配符标识符:匹配任何值并丢弃它: case [_, var y, _]: print('The middle element is $y');

带括号的

(subpattern)

与带括号的表达式一样,模式中的括号可让您控制模式优先级,并在需要较高优先级的模式时插入较低优先级的模式。

例如,假设布尔常量 、 和 分别等于 、 和 : x y z true true false

// ...
x || y && z => 'matches true',
(x || y) && z => 'matches false',
// ...

在第一种情况下,逻辑与模式首先求值,因为逻辑与模式比逻辑或模式具有更高的优先级。在下一种情况下,逻辑或模式被括起来。它首先进行评估,这会导致不同的匹配。 y && z

列表

[subpattern1, subpattern2]

列表模式匹配实现 List 的值,然后递归地将其子模式与列表元素匹配,以按位置解构它们:

const a = 'a';
const b = 'b';
switch (obj) {
  // List pattern [a, b] matches obj first if obj is a list with two fields,
  // then if its fields match the constant subpatterns 'a' and 'b'.
  case [a, b]:
    print('$a, $b');
}

列表模式要求模式中的元素数量与整个列表匹配。但是,您可以使用剩余元素作为占位符来说明列表中任意数量的元素。

休息元件

列表模式可以包含一个剩余元素 (),它允许匹配任意长度的列表。 ...

var [a, b, ..., c, d] = [1, 2, 3, 4, 5, 6, 7];
// Prints "1 2 6 7".
print('$a $b $c $d');

剩余元素还可以有一个子模式,该子模式将与列表中其他子模式不匹配的元素收集到一个新列表中:

var [a, b, ...rest, c, d] = [1, 2, 3, 4, 5, 6, 7];
// Prints "1 2 [3, 4, 5] 6 7".
print('$a $b $rest $c $d');

Map

{"key": subpattern1, someConst: subpattern2}

映射模式匹配实现 Map 的值,然后递归地将其子模式与映射的键匹配以解构它们。

地图模式不需要模式匹配整个地图。映射模式会忽略映射包含的与该模式不匹配的任何键。

记录

(subpattern1, subpattern2)

(x: subpattern1, y: subpattern2)

记录模式匹配记录对象并解构其字段。如果该值不是与模式形状相同的记录,则匹配失败。否则,字段子模式将与记录中的相应字段进行匹配。

记录模式要求模式与整个记录匹配。要使用模式解构具有命名字段的记录,请在模式中包含字段名称:

var (myString: foo, myNumber: bar) = (myString: 'string', myNumber: 1);

可以省略 getter 名称,并从字段子模式中的变量模式或标识符模式推断出来。这些模式对都是等效的:

// Record pattern with variable subpatterns:
var (untyped: untyped, typed: int typed) = record;
var (:untyped, :int typed) = record;

switch (record) {
  case (untyped: var untyped, typed: int typed): // ...
  case (:var untyped, :int typed): // ...
}

// Record pattern wih null-check and null-assert subpatterns:
switch (record) {
  case (checked: var checked?, asserted: var asserted!): // ...
  case (:var checked?, :var asserted!): // ...
}

// Record pattern wih cast subpattern:
var (untyped: untyped as int, typed: typed as String) = record;
var (:untyped as int, :typed as String) = record;

目的

SomeClass(x: subpattern1, y: subpattern2)

对象模式根据给定的命名类型检查匹配的值,以使用对象属性上的 getter 来解构数据。如果值不具有相同的类型,它们就会被驳斥。

switch (shape) {
  // Matches if shape is of type Rect, and then against the properties of Rect.
  case Rect(width: var w, height: var h): // ...
}

可以省略 getter 名称,并从字段子模式中的变量模式或标识符模式推断:

// Binds new variables x and y to the values of Point's x and y properties.
var Point(:x, :y) = Point(1, 2);

对象模式不需要模式匹配整个对象。如果一个对象有模式不会解构的额外字段,它仍然可以匹配。

通配符

-

命名的模式是通配符,可以是变量模式或标识符模式,不会绑定或分配给任何变量。 _

在需要子模式以解构后续位置值的地方,它可用作占位符:

var list = [1, 2, 3];
var [_, two, _] = list;

当您想要测试值的类型但不将该值绑定到名称时,带有类型注释的通配符名称非常有用:

switch (record) {
  case (int _, String _):
    print('First field is int and second is String.');
}

Comments

Make a comment