パターン型
このページは、さまざまな種類のパターンに関するリファレンスです。パターンの仕組み、Dart での使用場所、一般的なユースケースの概要については、メインのパターンページをご覧ください。
パターンの優先順位
#演算子の優先順位と同様に、パターンの評価は優先順位ルールに従います。より優先順位の低いパターンを先に評価するには、括弧付きパターンを使用できます。
このドキュメントでは、パターンの型を優先順位の昇順でリストしています。
論理 OR パターンは 論理 AND パターンよりも優先順位が低く、論理 AND パターンは 関係パターンよりも優先順位が低くなります。
残りの基本パターンは、最も高い優先順位を共有します。コレクション型(レコード、リスト、および マップ)および オブジェクトパターンは他のデータを取り込むため、外部パターンとして最初に評価されます。
論理 OR
#subpattern1 || subpattern2
論理 OR パターンは、サブパターンを ||
で区切り、いずれかのブランチが一致する場合に一致します。ブランチは左から右に評価されます。ブランチが一致すると、残りは評価されません。
var isPrimary = switch (color) {
Color.red || Color.yellow || Color.blue => true,
_ => false
};
論理 OR パターンのサブパターンは変数をバインドできますが、ブランチは同じ変数のセットを定義する必要があります。これは、パターンが一致するときに評価されるブランチは 1 つだけであるためです。
論理 AND
#subpattern1 && subpattern2
&&
で区切られたパターンのペアは、両方のサブパターンが一致する場合にのみ一致します。左側のブランチが一致しない場合、右側のブランチは評価されません。
論理 AND パターンのサブパターンは変数をバインドできますが、パターンが一致した場合に両方ともバインドされるため、各サブパターンの変数は重複してはなりません。
switch ((1, 2)) {
// Error, both subpatterns attempt to bind 'b'.
case (var a, var b) && (var b, var c): // ...
}
関係
#== 式
< 式
関係パターンは、一致した値を、等価演算子または関係演算子(==
、!=
、<
、>
、<=
、および >=
)を使用して指定された定数と比較します。
パターンは、一致した値に適切な演算子を定数を引数として呼び出すと、true
を返す場合に一致します。
関係パターンは、特に論理 AND パターンと組み合わせると、数値範囲に一致させる場合に役立ちます。
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;
キャストパターンは、値が指定された型を持っていない場合、スローします。Null アサートパターンと同様に、これにより、デストラクトされた値の予想される型を強制的にアサートできます。
Null チェック
#subpattern?
Null チェックパターンは、最初に値が null でない場合に一致し、次に同じ値に対して内部パターンを一致させます。これにより、照合対象の nullable 値の non-nullable ベース型である型を持つ変数をバインドできます。
null
値をスローせずに照合失敗として扱うには、Null チェックパターンを使用します。
String? maybeString = 'nullable with base type String';
switch (maybeString) {
case var s?:
// 's' has type non-nullable String here.
}
値が null の場合に一致させるには、定数パターン null
を使用します。
Null アサート
#subpattern!
Null アサートパターンは、最初にオブジェクトが null でない場合に一致し、次に値で一致します。これにより、null ではない値は通過できますが、照合された値が null の場合は スローします。
null
値がサイレントに照合失敗として扱われないようにするには、照合中に Null アサートパターンを使用します。
List<String?> row = ['user', null];
switch (row) {
case ['user', var name!]: // ...
// 'name' is a non-nullable string here.
}
変数宣言パターンから null
値を排除するには、Null アサートパターンを使用します。
(int?, int?) position = (2, 3);
var (x!, y!) = position;
値が null の場合に一致させるには、定数パターン 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 は左から右にパターンの照合を開始します。
最初のパターンは、
x
がtrue
と一致するため、true
と一致します。2 番目のパターンは、
x
がtrue
と一致するため、true
と一致します。3番目のパターンは、
x
がtrue
にマッチするため、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
はマッチしません。
リスト
#[サブパターン1, サブパターン2]
リストパターンは、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');
}
リストパターンでは、パターン内の要素数がリスト全体の要素数と一致する必要があります。ただし、レスト要素をプレースホルダーとして使用して、リスト内の任意の数の要素に対応できます。
レスト要素
#リストパターンには、任意の長さのリストにマッチできる1つのレスト要素(...
)を含めることができます。
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');
マップ
#{"key": サブパターン1, someConst: サブパターン2}
マップパターンは、Map
を実装する値にマッチし、次にそのサブパターンをマップのキーに対して再帰的にマッチさせ、キーを分解します。
マップパターンでは、パターンがマップ全体にマッチする必要はありません。マップパターンは、パターンにマッチしないマップに含まれるキーを無視します。
レコード
#(サブパターン1, サブパターン2)
(x: サブパターン1, y: サブパターン2)
レコードパターンは、レコードオブジェクトにマッチし、そのフィールドを分解します。値がパターンと同じ形状のレコードでない場合、マッチは失敗します。それ以外の場合は、フィールドサブパターンがレコード内の対応するフィールドとマッチされます。
レコードパターンでは、パターンがレコード全体にマッチする必要があります。名前付きフィールドを持つレコードをパターンを使用して分解するには、パターンにフィールド名を含めます。
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.5.3を反映しています。 ページは2024-06-27に最終更新されました。 ソースを表示 または 問題を報告する。