模式類型
此頁面是不同種類模式的參考。如需瞭解模式如何運作、在 Dart 中可以使用它們的位置以及常見的用例,請造訪主要的模式頁面。
模式優先順序
#類似於運算子優先順序,模式評估遵循優先順序規則。您可以使用括號模式先評估較低優先順序的模式。
此文件以遞增優先順序列出模式類型
邏輯或
#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): // ...
}
關係
#== 運算式
< 運算式
關係模式會使用任何相等或關係運算子(==
、!=
、<
、>
、<=
和 >=
)將相符的值與給定的常數進行比較。
當以常數作為引數在相符的值上呼叫適當的運算子傳回 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',
_ => ''
};
}
轉型
#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
。
空值斷言
#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
。
常數
#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);
- 比對內容:視為具名常數模式 (除非其名稱是
_
)dartconst c = 1; switch (2) { case c: print('match $c'); default: print('no match'); // Prints "no match". }
- 任何內容中的萬用字元識別符號:比對任何值並捨棄它:
case [_, var y, _]: print('中間元素是 $y');
括號
#(subpattern)
如同括號運算式,模式中的括號可讓您控制模式優先順序,並在預期較高優先順序的模式時插入較低優先順序的模式。
例如,假設布林常數 x
、y
和 z
分別等於 true
、true
和 false
。雖然下列範例類似於布林運算式評估,但此範例比對模式。
// ...
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 從左至右開始比對模式。
第一個模式會符合
true
,因為x
符合true
。第二個模式會符合
true
,因為x
符合true
。第三個模式會符合
true
,因為x
符合true
。第四個模式
(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
的值,然後以遞迴方式針對清單的元素比對其子模式,以依位置解構它們
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": 子模式1, someConst: 子模式2}
Map 模式會匹配實作 Map
的值,然後遞迴地將其子模式與 Map 的鍵進行匹配,以解構它們。
Map 模式不要求模式必須匹配整個 Map。Map 模式會忽略 Map 中包含的任何未被模式匹配的鍵。
記錄
#(子模式1, 子模式2)
(x: 子模式1, y: 子模式2)
記錄模式會匹配一個 record 物件並解構其欄位。如果該值不是具有與模式相同形狀的 record,則匹配失敗。否則,欄位子模式會與 record 中對應的欄位進行匹配。
記錄模式要求模式必須匹配整個 record。若要使用模式解構具有命名欄位的 record,請在模式中包含欄位名稱。
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 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 解構資料。如果該值不具有相同的類型,則會反駁。
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.');
}
除非另有說明,否則本網站上的文件反映的是 Dart 3.6.0。 頁面最後更新於 2024-06-27。 查看原始碼 或 回報問題。