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 Pattern —vardeclares a brand-new local variablenameand 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:
- Declaration context
var (a,b): Creates new variables - Assignment context
(a,b) = val: Overwrites existing variables - 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