Pattern

1. Logical OR Pattern A || B

Matches any single subpattern; all branches must define an identical set of variables.

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)

2. Logical AND Pattern A && B

Both subpatterns must match simultaneously; subpatterns cannot bind variables with identical names.

void main() {
  switch((2, 3)) {
    // Compile error: duplicate variable binding "b" across subpatterns
    // 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)

The pattern (>1, <5) enforces that the first number is greater than 1 and the second number is less than 5.

3. Relational Pattern < > <= >= == !=

Used for numeric range checks, often paired with && to restrict value bounds

String asciiCharType(int charCode) {
  const space = 32, zero = 48, nine = 57;
  return switch(charCode) {
    < space => "Control Character",
    == space => "Space",
    > space && < zero => "Punctuation",
    >= zero && <= nine => "Digit",
    _ => "Other"
  };
}
void main() {
  print(asciiCharType(50)); // Digit
  print(asciiCharType(33)); // Punctuation
}Code language: Dart (dart)

This example utilizes the ASCII standard for encoding control characters, numerals and other symbols. The charCode passed to the switch statement follows these rules: values below 32 are control characters, exactly 32 is a space, values between 32 and 48 are punctuation, values from 48 to 57 inclusive are digits, and all remaining values fall under “Other”.

4. Type Cast Pattern sub as Type

Enforces explicit type casting mid-destructuring; throws a runtime exception if the type mismatch occurs

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)

In this example, the record rec is destructured into i and s. If the first element is not an int or the second element is not a String, a runtime exception will be thrown.

See the failing example below:

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)

5. Null-Check Pattern sub?

Only matches non-null values; inner variables are automatically promoted to non-nullable types. Null values fail matching silently without exceptions.

void main() {
  String? str = "test";
  switch(str) {
    case var s?:
      print(s.length); // s is non-null String, outputs 4
    case null:
      print("Null Value");
  }
}Code language: Dart (dart)

6. Null Assert Pattern sub!

Matches only non-null values; throws a runtime exception immediately if the value is null

void main() {
  List<String?> row = ["user", "bob"];
  switch(row) {
    case ["user", var name!]:
      print(name); // name is non-null String
  }

  // Usage in variable destructuring
  (int?, int?) pos = (2, 3);
  var (x!, y!) = pos;
  print(x + y);
}Code language: Dart (dart)

Breakdown of var name!

  • var name: Variable Patternvar declares a brand-new local variable name and binds the matched value to it on successful match;
  • !: Postfix Null Assert Pattern — enforces the value must not be null; throws a runtime error if null is encountered.

Combined meaning: var name! creates a new variable name and simultaneously asserts its value cannot be null.

7. Constant Pattern

Literals, named constants, const constructors and const collections all qualify as constant patterns; a match occurs when values are strictly equal.

Supported types: numbers, strings, booleans, named constants, const objects / lists

void main() {
  const target = 10;
  int num = 10;
  switch(num) {
    case 1: print("One");
    case target: print("Matches constant 10");
    case const [1,2]: print("Constant List");
    default: print("Other");
  }
}Code language: Dart (dart)

Program Output

Matches constant 10

8. Variable Pattern var x / int x / final x

Binds a new local variable upon successful match; adding a type annotation validates the value type simultaneously

void main() {
  switch((99, "dart")) {
    case (int a, String b):
      print("$a $b"); // 99 dart
    case (int a, int b):
      print("Two Numeric Values");
  }
}Code language: Dart (dart)

9. Identifier Pattern

Behavior splits into three distinct contexts:

  1. Declaration context var (a,b): Creates new variables
  2. Assignment context (a,b) = val: Overwrites existing variables
  3. Switch matching context: Treated as a constant (exception: _)
void main() {
  const c = 5;
  int val = 2;
  switch(val) {
    case c: print("Matches constant c");
    default: print("No Match"); // This line executes
  }
}
Code language: Dart (dart)

10. Parenthesized Pattern (subPattern)

Adjusts pattern operator precedence to clarify evaluation order between || and &&

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)

11. List Pattern

Matches List instances and destructures elements by position; supports ... rest operator to capture arbitrary trailing elements

1. Basic List Matching
void main() {
  const a = "a", b = "b";
  var arr = ["a", "b"];
  switch(arr) {
    case [a, b]: print("Match Found");
    default: print("No Match");
  }
}Code language: Dart (dart)
2. Rest Operator for Remaining Elements
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)

12. Map Pattern {"key": subP}

Matches Map objects and validates only specified keys; throws StateError if a target key is missing, ignores extra unmentioned keys

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

13. Record Pattern

Two variants available: positional records (p1,p2) and named records (k:p1,k2:p2)

Supports shorthand :var syntax to omit repeated field names

void main() {
  // Positional record destructuring
  var (name, age) = ("Doug", 25);
  // Shorthand destructuring for named fields
  final (:name, :age) = (name: "Tom", age: 18);
}
Code language: JavaScript (javascript)

14. Object Pattern Class(prop: p)

Matches objects of a specified type and destructures getter properties; supports the :var shorthand syntax

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)

15. Wildcard Pattern _

Matches any value without binding a variable; used as placeholders or to validate types without extracting values

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

  switch((10, "abc")) {
    case (int _, String _):
      print("Type Match Succeeded");
  }
}Code language: JavaScript (javascript)

Pattern

Leave a Reply

Your email address will not be published. Required fields are marked *