目錄

模式類型

此頁面是不同種類模式的參考。如需瞭解模式如何運作、在 Dart 中可以使用它們的位置以及常見的用例,請造訪主要的模式頁面。

模式優先順序

#

類似於運算子優先順序,模式評估遵循優先順序規則。您可以使用括號模式先評估較低優先順序的模式。

此文件以遞增優先順序列出模式類型

邏輯或

#

subpattern1 || subpattern2

邏輯或模式會以 || 分隔子模式,如果任何分支符合,則會符合。分支會由左至右評估。一旦分支符合,其餘分支就不會評估。

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

邏輯或模式中的子模式可以繫結變數,但分支必須定義相同的變數集,因為當模式符合時,只會評估一個分支。

邏輯和

#

subpattern1 && subpattern2

&& 分隔的一對模式只有在兩個子模式都符合時才會符合。如果左分支不符合,則不會評估右分支。

邏輯和模式中的子模式可以繫結變數,但每個子模式中的變數不得重疊,因為如果模式符合,它們都會被繫結

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

關係

#

== 運算式

< 運算式

關係模式會使用任何相等或關係運算子(==!=<><=>=)將相符的值與給定的常數進行比較。

當以常數作為引數在相符的值上呼叫適當的運算子傳回 true 時,模式符合。

關係模式適用於比對數值範圍,尤其是在與邏輯和模式結合使用時

dart
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',
    _ => ''
  };
}

轉型

#

foo as String

轉型模式可讓您在解構過程中插入類型轉型,然後再將值傳遞給另一個子模式

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

如果值不具有宣告的類型,轉型模式會擲回例外。如同空值斷言模式,這可讓您強制斷言某些解構值的預期類型。

空值檢查

#

subpattern?

空值檢查模式會先在值不是空值時符合,然後再針對相同的值比對內部模式。它們可讓您繫結其類型為被比對之可空值基礎類型的非空值變數。

若要將 null 值視為不符合而不擲回例外,請使用空值檢查模式。

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

若要在值空值時符合,請使用常數模式 null

空值斷言

#

subpattern!

空值斷言模式會先在物件不是空值時符合,然後再針對該值符合。它們允許非空值通過,但如果相符的值是空值,則會擲回例外。

若要確保 null 值不會被靜默地視為不符合,請在比對時使用空值斷言模式

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

若要從變數宣告模式中消除 null 值,請使用空值斷言模式

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

var (x!, y!) = position;

若要在值空值時符合,請使用常數模式 null

常數

#

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

當值等於常數時,常數模式符合

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

您可以將簡單的常值和對具名常數的參考直接用作常數模式

  • 數字常值 (12345.56)
  • 布林常值 (true)
  • 字串常值 ('string')
  • 具名常數 (someConstantmath.pidouble.infinity)
  • 常數建構函式 (const Point(0, 0))
  • 常數集合常值 (const []const {1, 2})

更複雜的常數運算式必須加上括號並以 const 作為前綴 (const (1 + 2))

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

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

變數

#

var bar、String str、final int _

變數模式會將新變數繫結至已比對或解構的值。它們通常會作為解構模式的一部分出現,以擷取解構的值。

變數的作用域位於只有在模式符合時才可到達的程式碼區域中。

dart
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.
}

類型化的變數模式只有在相符的值具有宣告的類型時才會符合,否則會失敗

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

您可以使用萬用字元模式作為變數模式。

識別符號

#

foo、_

識別符號模式的行為可能像常數模式或像變數模式,視其出現的內容而定

  • 宣告內容:使用識別符號名稱宣告新變數:var (a, b) = (1, 2);
  • 指派內容:指派給具有識別符號名稱的現有變數:(a, b) = (3, 4);
  • 比對內容:視為具名常數模式 (除非其名稱是 _)
    dart
    const c = 1;
    switch (2) {
      case c:
        print('match $c');
      default:
        print('no match'); // Prints "no match".
    }
  • 任何內容中的萬用字元識別符號:比對任何值並捨棄它:case [_, var y, _]: print('中間元素是 $y');

括號

#

(subpattern)

如同括號運算式,模式中的括號可讓您控制模式優先順序,並在預期較高優先順序的模式時插入較低優先順序的模式。

例如,假設布林常數 xyz 分別等於 truetruefalse。雖然下列範例類似於布林運算式評估,但此範例比對模式。

dart
// ...
x || y => 'matches true',
x || y && z => 'matches true',
x || (y && z) => 'matches true',
// `x || y && z` is the same thing as `x || (y && z)`.
(x || y) && z => 'matches nothing',
// ...

Dart 從左至右開始比對模式。

  1. 第一個模式會符合 true,因為 x 符合 true

  2. 第二個模式會符合 true,因為 x 符合 true

  3. 第三個模式會符合 true,因為 x 符合 true

  4. 第四個模式 (x || y) && z 沒有相符的項目。

    • x 符合 true,因此 Dart 不會嘗試比對 y
    • 雖然 (x || y) 符合 true,但 z 不符合 true
    • 因此,模式 (x || y) && z 不符合 true
    • 子模式 (x || y) 不符合 false,因此 Dart 不會嘗試比對 z
    • 因此,模式 (x || y) && z 不符合 false
    • 結論是,(x || y) && z 沒有相符的項目。

清單

#

[subpattern1, subpattern2]

清單模式會比對實作List的值,然後以遞迴方式針對清單的元素比對其子模式,以依位置解構它們

dart
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');
}

清單模式要求模式中的元素數量必須比對整個清單。但是,您可以使用其餘元素作為預留位置,以考慮清單中的任何元素數量。

其餘元素

#

清單模式可以包含一個其餘元素 (...),這允許比對任意長度的清單。

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

剩餘元素也可以有一個子模式,將列表中不符合其他子模式的元素收集到一個新的列表中。

dart
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": 子模式1, someConst: 子模式2}

Map 模式會匹配實作 Map 的值,然後遞迴地將其子模式與 Map 的鍵進行匹配,以解構它們。

Map 模式不要求模式必須匹配整個 Map。Map 模式會忽略 Map 中包含的任何未被模式匹配的鍵。

記錄

#

(子模式1, 子模式2)

(x: 子模式1, y: 子模式2)

記錄模式會匹配一個 record 物件並解構其欄位。如果該值不是具有與模式相同形狀的 record,則匹配失敗。否則,欄位子模式會與 record 中對應的欄位進行匹配。

記錄模式要求模式必須匹配整個 record。若要使用模式解構具有命名欄位的 record,請在模式中包含欄位名稱。

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

可以省略 getter 名稱,並從欄位子模式中的變數模式識別符號模式中推斷。這幾對模式是等效的。

dart
// 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 with null-check and null-assert subpatterns:
switch (record) {
  case (checked: var checked?, asserted: var asserted!): // ...
  case (:var checked?, :var asserted!): // ...
}

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

物件

#

SomeClass(x: 子模式1, y: 子模式2)

物件模式會根據給定的命名類型檢查匹配的值,以使用物件屬性的 getter 解構資料。如果該值不具有相同的類型,則會反駁

dart
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 名稱,並從欄位子模式中的變數模式識別符號模式中推斷。

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

物件模式不要求模式必須匹配整個物件。如果物件具有模式未解構的額外欄位,它仍然可以匹配。

萬用字元

#

_

名為 _ 的模式是一個萬用字元,可以是變數模式識別符號模式,不會繫結或指派給任何變數。

在需要子模式才能解構後面的位置值的情況下,它可以用作預留位置。

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

當您想要測試值的類型,但不想將該值繫結到名稱時,帶有類型註釋的萬用字元名稱很有用。

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