Pattern

一、論理ORパターン A || B

いずれかのサブパターンに一致すればマッチします。全ての分岐で同一の変数セットを定義する必要があります。

enum Color { red, yellow, blue, green }
void main() {
  Color c = Color.red;
  bool primary = switch(c) {
    Color.red || Color.yellow || Color.blue => true,
    _ => false
  };
  print(primary); // true
}Code language: Dart (dart)

二、論理ANDパターン A && B

二つのサブパターンが同時に一致しなければなりません。サブパターン同士で同名変数を束縛することはできません。

void main() {
  switch((2, 3)) {
    // コンパイルエラー:両方のサブパターンで変数bを束縛、名前衝突が発生
    // case (var a, var b) && (var b, var c): print("ok");
    case (var a, var b) && (>1, <5):
      print("a=$a,b=$b"); // a=2,b=3
  }
}Code language: Dart (dart)

この (>1, <5) は1番目の数値が1より大きく、2番目の数値が5未満であることを要求する記述です。

三、比較演算子パターン < > <= >= == !=

数値の範囲判定に使用し、&& と組み合わせて値の範囲を制限するのが一般的です。

String asciiCharType(int charCode) {
  const space = 32, zero = 48, nine = 57;
  return switch(charCode) {
    < space => "制御文字",
    == space => "スペース",
    > space && < zero => "記号",
    >= zero && <= nine => "数字",
    _ => "その他"
  };
}
void main() {
  print(asciiCharType(50)); // 数字
  print(asciiCharType(33)); // 記号
}Code language: Dart (dart)

上記サンプルではASCIIコードを使用し、制御文字・数字・記号などを分類しています。switchに渡すcharCodeの判定ルール:32未満は制御文字、32はスペース、32超48未満は記号、48以上57以下は数字、それ以外はその他となります。

四、型キャストパターン sub as Type

デストラクチャリング途中で強制的に型変換を実行し、型が不一致の場合実行時例外をスローします。

void main() {
  (num, Object) rec = (10, "hello");
  var (i as int, s as String) = rec;
  print(i + 5); // 15
  print(s.toUpperCase()); // HELLO
}Code language: Dart (dart)

この例ではrecをiとsに分解しています。recの1要素目がint型ではない、または2要素目が文字列でない場合、実行時例外が発生します。

以下にエラーが発生する例を示します。

void main() {
  (num, Object) rec = (9.3, "hello");
  var (i as int, s as String) = rec;
  print(i + 5); // 15
  print(s.toUpperCase()); // HELLO
}Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
type 'double' is not a subtype of type 'int' in type cast
#0      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:3:10)
#1      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

五、Nullチェックパターン sub?

値が非nullの場合のみマッチし、内部変数は自動的にNull非許容型に昇格します。nullの場合はマッチ失敗となり、例外は発生しません。

void main() {
  String? str = "test";
  switch(str) {
    case var s?:
      print(s.length); // sはNull非許容文字列、出力4
    case null:
      print("null値");
  }
}Code language: Dart (dart)

六、Nullアサーションパターン sub!

値が非nullの場合のみマッチし、値がnullだった場合は即時に実行時例外を送出します。

void main() {
  List<String?> row = ["user", "bob"];
  switch(row) {
    case ["user", var name!]:
      print(name); // nameはNull非許容文字列
  }

  // 変数デストラクチャリングでの利用
  (int?, int?) pos = (2, 3);
  var (x!, y!) = pos;
  print(x + y);
}Code language: Dart (dart)

var name! の解説

  • var name変数パターンvar で新しいローカル変数 name を宣言し、マッチ成功時に値を束縛します;
  • !後置Nullアサーションパターン — 対象の値がnullでないことを強制し、nullの場合は実行時エラーを発生させます。

組み合わせた意味:var name! は新規変数nameを作成すると同時に、値がnullでないことを強制保証します。

七、定数パターン

リテラル、名前付き定数、constコンストラクタ、constコレクションは全て定数パターンに該当し、値が完全一致すればマッチします。

対応種類:数値、文字列、真偽値、名前付き定数、const オブジェクト / リスト

void main() {
  const target = 10;
  int num = 10;
  switch(num) {
    case 1: print("1");
    case target: print("定数10に一致");
    case const [1,2]: print("定数リスト");
    default: print("その他");
  }
}Code language: Dart (dart)

実行結果

定数10に一致

八、変数パターン var x / int x / final x

マッチ成功時に新しいローカル変数に値を束縛し、型注釈を付けると同時に型検証を行います。

void main() {
  switch((99, "dart")) {
    case (int a, String b):
      print("$a $b"); // 99 dart
    case (int a, int b):
      print("二つの数値");
  }
}Code language: Dart (dart)

九、識別子パターン

使用コンテキストにより3通りの動作に分かれます:

  1. 宣言コンテキスト var (a,b):新しい変数を作成
  2. 代入コンテキスト (a,b) = val:既存変数の値を上書き
  3. switchマッチコンテキスト:定数として扱う(_ は例外)
void main() {
  const c = 5;
  int val = 2;
  switch(val) {
    case c: print("定数cに一致");
    default: print("不一致"); // こちらが出力される
  }
}
Code language: Dart (dart)

十、括弧付きパターン (subPattern)

パターン演算子の優先順位を変更し、||&& の評価順序を明確に分けます。

void main() {
  bool x = true, y = true, z = false;
  bool test = switch(true) {
    (x || y) && z => true,
    _ => false
  };
  print(test); // false
}
Code language: Dart (dart)

十一、リストパターン

Listコレクションにマッチし、位置順に要素を分解します。... rest演算子で任意数の残り要素を取得可能です。

1. 基本的なリストマッチ
void main() {
  const a = "a", b = "b";
  var arr = ["a", "b"];
  switch(arr) {
    case [a, b]: print("マッチ成功");
    default: print("マッチしない");
  }
}Code language: Dart (dart)
2. restによる残り要素取得
void main() {
  var [a, b, ...rest, c, d] = [1,2,3,4,5,6,7];
  print("$a $b $rest $c $d"); // 1 2 [3, 4, 5] 6 7
}
Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
1 2 [3, 4, 5] 6 7Code language: CSS (css)

十二、Mapパターン {"key": subP}

Mapオブジェクトにマッチし、指定したキーのみ検証します。対象キーが存在しない場合は StateError が発生し、記載のない余分なキーは無視されます。

void main() {
  var data = {"user": ["Lily", 13]};
  if(data case {"user": [String name, int age]}) {
    print("$name $age"); //Lily 13
  }
}Code language: JavaScript (javascript)

十三、レコードパターン

二種類存在:位置指定レコード (p1,p2)、名前付きレコード (k:p1,k2:p2)

:var 省略記法に対応し、重複するフィールド名を省略できます。

void main() {
  // 位置指定レコード分解
  var (name, age) = ("Doug", 25);
  // 名前付きフィールド省略記法分解
  final (:name, :age) = (name: "Tom", age: 18);
}
Code language: JavaScript (javascript)

十四、オブジェクトパターン Class(prop: p)

指定した型のオブジェクトにマッチし、Getterプロパティを分解します。:var 省略記法に対応。

class Point {
  final int x, y;
  Point(this.x, this.y);
}

void main() {
  Point p = Point(10, 20);
  var Point(:x, :y) = p;
  print("$x $y");
}
Code language: JavaScript (javascript)

十五、ワイルドカードパターン _

任意の値にマッチし、変数を束縛しません。プレースホルダーや型のみ検証し値を取得しない場面で使用します。

void main() {
  var arr = [1,2,3];
  var [_, mid, _] = arr;
  print(mid); // 2

  switch((10, "abc")) {
    case (int _, String _):
      print("型マッチ成功");
  }
}Code language: JavaScript (javascript)

Pattern

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です