メインコンテンツにスキップ

パターン型

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

パターンの優先度

#

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

このドキュメントでは、パターンの種類を優先度の昇順でリストします。

  • 論理和パターンは論理積パターンよりも優先度が低く、論理積パターンは比較パターンよりも優先度が低く、といった具合です。

  • 後置単項パターン(キャストnullチェックnullアサート)は、同じ優先度レベルを共有します。

  • 残りのプライマリパターンは、最も高い優先度を共有します。コレクション型(レコードリストマップ)およびオブジェクトパターンは他のデータを包含するため、まず外側のパターンとして評価されます。

論理和 (Logical-or)

#

subpattern1 || subpattern2

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

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

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

論理積 (Logical-and)

#

subpattern1 && subpattern2

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

論理積パターンのサブパターンは変数を束縛できますが、パターンが一致した場合に両方が束縛されるため、各サブパターンの変数は重複してはいけません。

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

比較 (Relational)

#

== expression

< expression

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

パターンは、一致した値に対して適切な演算子を定数を引数として呼び出したときに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',
    _ => '',
  };
}

キャスト (Cast)

#

foo as String

キャストパターンにより、値を別のサブパターンに渡す前に、デストラクチャリングの途中に型キャストを挿入できます。

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

値が指定された型でない場合、キャストパターンはスローされます。nullアサートパターンと同様に、これにより、デストラクチャリングされた値の期待される型を強制的にアサートできます。

Nullチェック (Null-check)

#

subpattern?

Nullチェックパターンは、値がnullでない場合に最初に一致し、その後、その同じ値に対して内部パターンを一致させます。null許容値のnull許容でない基底型を持つ変数を束縛できます。

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アサート (Null-assert)

#

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を使用してください。

定数 (Constant)

#

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]: // ...

変数 (Variable)

#

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): // ...
}

変数パターンとしてワイルドカードパターンを使用できます。

識別子 (Identifier)

#

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('The middle element is $y');

括弧付き (Parenthesized)

#

(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. 最初のパターンは、xtrueに一致するため、truexに一致させます。

  2. 2番目のパターンは、xtrueに一致するため、truexに一致させます。

  3. 3番目のパターンは、xtrueに一致するため、truexに一致させます。

  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には一致がありません。

リスト (List)

#

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

リストパターンは、パターン内の要素数がリスト全体と一致することを要求します。ただし、残余要素を使用して、リスト内の任意の数の要素を考慮するためのプレースホルダーとして使用できます。

残余要素 (Rest element)

#

リストパターンには、任意の長さのリストを一致させることができる残余要素(...)を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');

マップ (Map)

#

{"key": subpattern1, someConst: subpattern2}

マップパターンは、Mapを実装する値を一致させ、その後、マップのキーに対してサブパターンを再帰的に一致させてデストラクチャリングします。

マップパターンは、パターンがマップ全体と一致することを要求しません。マップパターンは、マップに含まれるがパターンによって一致されないキーを無視します。マップに存在しないキーを一致させようとすると、StateErrorがスローされます。

dart
final {'foo': int? foo} = {};

レコード (Record)

#

(subpattern1, subpattern2)

(x: subpattern1, y: subpattern2)

レコードパターンは、レコードオブジェクトを一致させ、そのフィールドをデストラクチャリングします。値がパターンの形状と同じレコードでない場合、一致は失敗します。それ以外の場合は、フィールドサブパターンがレコード内の対応するフィールドに対して一致されます。

レコードパターンは、パターンがレコード全体と一致することを要求します。パターンを使用して名前付きフィールドを持つレコードをデストラクチャリングするには、パターンにフィールド名を含めます。

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;

オブジェクト (Object)

#

SomeClass(x: subpattern1, y: subpattern2)

オブジェクトパターンは、一致した値を指定された名前付き型に対してチェックし、オブジェクトのプロパティの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);

オブジェクトパターンは、パターンがオブジェクト全体と一致することを要求しません。オブジェクトにパターンがデストラクチャリングしない余分なフィールドがある場合でも、一致させることができます。

ワイルドカード (Wildcard)

#

_

_という名前のパターンはワイルドカードであり、変数に束縛または代入しない変数パターンまたは識別子パターンです。

後続の位置値でデストラクチャリングするためにサブパターンが必要な場所で、プレースホルダーとして役立ちます。

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

型注釈付きのワイルドカード名は、値の型をテストしたいが、値を名前に束縛したくない場合に便利です。

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