目次

パターン型

このページは、さまざまな種類のパターンに関するリファレンスです。パターンの仕組み、Dart での使用場所、一般的なユースケースの概要については、メインのパターンページをご覧ください。

パターンの優先順位

#

演算子の優先順位と同様に、パターンの評価は優先順位ルールに従います。より優先順位の低いパターンを先に評価するには、括弧付きパターンを使用できます。

このドキュメントでは、パターンの型を優先順位の昇順でリストしています。

  • 論理 OR パターンは 論理 AND パターンよりも優先順位が低く、論理 AND パターンは 関係パターンよりも優先順位が低くなります。

  • 接尾辞単項パターン(キャストNull チェック、および Null アサート)は、同じレベルの優先順位を共有します。

  • 残りの基本パターンは、最も高い優先順位を共有します。コレクション型(レコードリスト、および マップ)および オブジェクトパターンは他のデータを取り込むため、外部パターンとして最初に評価されます。

論理 OR

#

subpattern1 || subpattern2

論理 OR パターンは、サブパターンを || で区切り、いずれかのブランチが一致する場合に一致します。ブランチは左から右に評価されます。ブランチが一致すると、残りは評価されません。

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

論理 OR パターンのサブパターンは変数をバインドできますが、ブランチは同じ変数のセットを定義する必要があります。これは、パターンが一致するときに評価されるブランチは 1 つだけであるためです。

論理 AND

#

subpattern1 && subpattern2

&& で区切られたパターンのペアは、両方のサブパターンが一致する場合にのみ一致します。左側のブランチが一致しない場合、右側のブランチは評価されません。

論理 AND パターンのサブパターンは変数をバインドできますが、パターンが一致した場合に両方ともバインドされるため、各サブパターンの変数は重複してはなりません。

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

関係

#

== 式

< 式

関係パターンは、一致した値を、等価演算子または関係演算子(==!=<><=、および >=)を使用して指定された定数と比較します。

パターンは、一致した値に適切な演算子を定数を引数として呼び出すと、true を返す場合に一致します。

関係パターンは、特に論理 AND パターンと組み合わせると、数値範囲に一致させる場合に役立ちます。

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;

キャストパターンは、値が指定された型を持っていない場合、スローします。Null アサートパターンと同様に、これにより、デストラクトされた値の予想される型を強制的にアサートできます。

Null チェック

#

subpattern?

Null チェックパターンは、最初に値が null でない場合に一致し、次に同じ値に対して内部パターンを一致させます。これにより、照合対象の nullable 値の non-nullable ベース型である型を持つ変数をバインドできます。

null 値をスローせずに照合失敗として扱うには、Null チェックパターンを使用します。

dart
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 アサートパターンを使用します。

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

変数宣言パターンから null 値を排除するには、Null アサートパターンを使用します。

dart
(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)

定数パターンは、値が定数と等しい場合に一致します。

dart
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))

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)

括弧付き式と同様に、パターン内の括弧を使用すると、パターンの優先順位を制御し、より優先順位の高いパターンが期待される場合に、より優先順位の低いパターンを挿入できます。

たとえば、ブール定数 xy、および z がそれぞれ truetrue、および false に等しいとします。次の例はブール式の評価に似ていますが、この例はパターンに一致します。

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. 最初のパターンは、xtrue と一致するため、true と一致します。

  2. 2 番目のパターンは、xtrue と一致するため、true と一致します。

  3. 3番目のパターンは、xtrueにマッチするため、trueにマッチします。

  4. 4番目のパターン(x || y) && zはマッチしません。

    • xtrueにマッチするため、Dartはyとのマッチを試みません。
    • (x || y)trueにマッチしますが、ztrueにマッチしません。
    • したがって、パターン(x || y) && ztrueにマッチしません。
    • サブパターン(x || y)falseにマッチしないため、Dartはzとのマッチを試みません。
    • したがって、パターン(x || y) && zfalseにマッチしません。
    • 結論として、(x || y) && zはマッチしません。

リスト

#

[サブパターン1, サブパターン2]

リストパターンは、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');
}

リストパターンでは、パターン内の要素数がリスト全体の要素数と一致する必要があります。ただし、レスト要素をプレースホルダーとして使用して、リスト内の任意の数の要素に対応できます。

レスト要素

#

リストパターンには、任意の長さのリストにマッチできる1つのレスト要素(...)を含めることができます。

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

マップ

#

{"key": サブパターン1, someConst: サブパターン2}

マップパターンは、Mapを実装する値にマッチし、次にそのサブパターンをマップのキーに対して再帰的にマッチさせ、キーを分解します。

マップパターンでは、パターンがマップ全体にマッチする必要はありません。マップパターンは、パターンにマッチしないマップに含まれるキーを無視します。

レコード

#

(サブパターン1, サブパターン2)

(x: サブパターン1, y: サブパターン2)

レコードパターンは、レコードオブジェクトにマッチし、そのフィールドを分解します。値がパターンと同じ形状のレコードでない場合、マッチは失敗します。それ以外の場合は、フィールドサブパターンがレコード内の対応するフィールドとマッチされます。

レコードパターンでは、パターンがレコード全体にマッチする必要があります。名前付きフィールドを持つレコードをパターンを使用して分解するには、パターンにフィールド名を含めます。

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