This skill defines how to correctly use Dart 3 language features: branches, patterns, pattern types, and records.
// Standard if
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else {
grade = 'C';
}
// if-case: match and destructure against a single pattern
if (pair case [int x, int y]) {
print('$x, $y');
}
if conditions must evaluate to a bool.if-case, variables declared in the pattern are scoped to the matching branch.else branch (if present).switch (command) {
case 'quit':
quit();
case 'start' || 'begin': // logical-or pattern
startGame();
default:
print('Unknown command');
}
case body executes and jumps to the end — break is not required.continue, throw, or return.default or _ to handle unmatched values.break to prevent fallthrough in an empty case.continue with a label for non-sequential fallthrough.case a || b) to share a body between cases.final color = switch (shape) {
Circle() => 'red',
Square() => 'blue',
_ => 'unknown',
};
case; use => for bodies; separate cases with commas._ (not default).switch statements and expressions at compile time.default/_, enums, or sealed types to satisfy exhaustiveness.sealed class Shape {}
class Circle extends Shape {}
class Square extends Shape {}
// Dart knows all subtypes — no default needed:
String describe(Shape s) => switch (s) {
Circle() => 'circle',
Square() => 'square',
};
switch (point) {
case (int x, int y) when x == y:
print('Diagonal: $x');
case (int x, int y):
print('$x, $y');
}
when condition after a pattern to further constrain matching.if-case, switch statements, and switch expressions.false, execution proceeds to the next case.Patterns represent the shape of a value for matching and destructuring.
// Variable declaration
var (a, [b, c]) = ('str', [1, 2]);
// Variable assignment (swap)
(b, a) = (a, b);
// for-in loop destructuring
for (final MapEntry(:key, :value) in map.entries) { ... }
// switch / if-case (see Branches section)
_ ignores parts of a matched value....) in list patterns ignore remaining elements.var Foo(:one, :two) = myFoo;
if (data case {'user': [String name, int age]}) {
print('$name, $age');
}
| Pattern | Syntax | Description |
|---|---|---|
| Logical-or | p1 || p2 |
Matches if any branch matches. All branches must bind the same variables. |
| Logical-and | p1 && p2 |
Matches if both match. Variable names must not overlap. |
| Relational | == c, < c, >= c |
Compares value to a constant. Combine with && for ranges. |
| Cast | subpattern as Type |
Asserts type, then matches inner pattern. Throws if type mismatch. |
| Null-check | subpattern? |
Matches non-null; binds non-nullable type. |
| Null-assert | subpattern! |
Matches non-null or throws. Use in declarations to eliminate nulls. |
| Constant | 42, 'str', const Foo() |
Matches if value equals the constant. |
| Variable | var name, final Type name |
Binds matched value to a new variable. Typed form only matches the declared type. |
| Wildcard | _, Type _ |
Matches any value without binding. |
| Parenthesized | (subpattern) |
Controls precedence. |
| List | [p1, p2] |
Matches lists by position. Length must match unless a rest element is used. |
| Rest element | ..., ...rest |
Matches arbitrary-length tails or collects remaining elements. |
| Map | {'key': subpattern} |
Matches maps by key. Missing keys throw StateError. |
| Record | (p1, p2), (x: p1, y: p2) |
Matches records by shape; field names can be omitted if inferred. |
| Object | ClassName(field: p) |
Matches by type and destructures via getters. Extra fields ignored. |
// Create
var record = ('first', a: 2, b: true, 'last');
// Type annotation
({int a, bool b}) namedRecord;
// Access
print(record.$1); // positional: 'first'
print(record.a); // named: 2
$1, $2, .name); no setters.hashCode and == are automatically defined.(String name, int age) userInfo(Map<String, dynamic> json) {
return (json['name'] as String, json['age'] as int);
}
var (name, age) = userInfo(json);
// Named fields:
final (:name, :age) = userInfo(json);
Use a record when:
Use a class when:
copyWith.typedef for record types to improve readability and maintainability.