flutter
/

Dart Patterns – Complete Guide with Examples

Last Sync: Today

On this page

17
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

Dart Patterns – Complete Guide with Examples

What are Patterns in Dart?

Introduced in Dart 3.0, patterns are a powerful feature that let you destructure data, test values, and bind variables in a concise and expressive way. Patterns can be used in several contexts: variable declarations (var (x, y) = point), switch statements and expressions, if-case statements, and for loops. Patterns bring many functional programming conveniences to Dart.

Basic Pattern Types

Dart supports a variety of pattern types. Here are the most common:

Wildcard Pattern (_)

The underscore _ matches any value but does not bind it to a variable. It's useful when you want to ignore a part of a structure.

DARTRead-only
1
void main() {
  var (_, y) = (10, 20); // ignore first field
  print(y); // 20
}

Variable Pattern

A variable pattern binds a value to a new variable. The variable can be var, final, or a specific type.

DARTRead-only
1
void main() {
  var (x, y) = (10, 20); // x and y are new variables
  print('$x, $y'); // 10, 20

  final (a, b) = (5, 6);
}

Constant Pattern

Matches a value exactly against a constant. Useful in switch cases and if-case.

DARTRead-only
1
void main() {
  const pi = 3.14;
  var value = 3.14;
  if (value == pi) { ... } // traditional
  // pattern equivalent in if-case:
  if (value case pi) {
    print('Matches pi');
  }
}

Logical Patterns (||, &&)

Combine subpatterns using || (or) and && (and). This allows you to match multiple possibilities.

DARTRead-only
1
void main() {
  int? maybeNull = null;
  if (maybeNull case 0 || 1) {
    print('0 or 1');
  } else if (maybeNull case null) {
    print('null');
  }
}

Relational Patterns (<, >, <=, >=, ==)

Compare values using relational operators. Useful for ranges in patterns.

DARTRead-only
1
void main() {
  int score = 85;
  switch (score) {
    case < 60: print('Fail'); break;
    case < 75: print('Pass'); break;
    case < 90: print('Merit'); break;
    default: print('Distinction');
  }
}

Cast Pattern (as)

Attempts to cast the value to a type. If the cast fails, the pattern does not match.

DARTRead-only
1
void main() {
  Object obj = 'Hello';
  if (obj case String s) {
    print('String length: ${s.length}');
  }
}

List Pattern

Destructures a list by matching elements. You can use _ to ignore elements and ... to match the rest.

DARTRead-only
1
void main() {
  var list = [1, 2, 3];
  var [a, b, c] = list;
  print('$a, $b, $c'); // 1, 2, 3

  // With rest
  var [first, ...rest] = [10, 20, 30];
  print('first=$first, rest=$rest'); // first=10, rest=[20, 30]

  // Match in switch
  switch (list) {
    case [1, 2, 3]: print('Exact match'); break;
    case [_, _, _]: print('Three elements'); break;
  }
}

Map Pattern

Destructures a map by matching key‑value pairs. Only the listed keys are extracted; extra keys are ignored.

DARTRead-only
1
void main() {
  var map = {'name': 'Alice', 'age': 30};
  var {'name': name, 'age': age} = map;
  print('$name is $age'); // Alice is 30

  // Using rest
  var {'name': n, ...} = map;
  print(n);
}

Record Pattern

Destructures a record by matching its fields. Both positional and named fields can be matched.

DARTRead-only
1
void main() {
  var point = (10, 20);
  var (x, y) = point;
  print('x=$x, y=$y');

  var person = (name: 'Bob', age: 25);
  var (name: n, age: a) = person;
  print('$n is $a');
}

Object Pattern

Matches against an object's type and extracts its fields using named getters (or properties). For example, you can extract the x and y fields from a Point instance.

DARTRead-only
1
class Point {
  final int x, y;
  Point(this.x, this.y);
}

void main() {
  Point p = Point(5, 7);
  if (p case Point(x: var x, y: var y)) {
    print('x=$x, y=$y');
  }
}

Guard Pattern (when)

A guard is an extra condition that must be true for a pattern to match. It can be added to any pattern in a switch or if-case.

DARTRead-only
1
void main() {
  var pair = (3, 4);
  switch (pair) {
    case (int x, int y) when x > y:
      print('x > y');
    case (int x, int y) when x < y:
      print('x < y');
    default:
      print('x == y');
  }
}

Pattern Usage in Switch

switch statements and switch expressions can now use patterns. Each case can be a pattern, and you can use guards.

DARTRead-only
1
void describe(dynamic value) {
  switch (value) {
    case int x when x > 0: print('Positive int $x');
    case int x: print('Non-positive int $x');
    case [_, _, ...]: print('List with at least two elements');
    case {'name': String n, 'age': int a}:
      print('Name: $n, Age: $a');
    default: print('Something else');
  }
}

Pattern Usage in if-case

if (value case pattern) allows you to conditionally match and bind variables in a single line.

DARTRead-only
1
void main() {
  var obj = (x: 5, y: 10);
  if (obj case (x: int x, y: int y) when x < y) {
    print('$x is less than $y');
  }
}

Patterns in For Loops

You can destructure elements in for loops using patterns.

DARTRead-only
1
void main() {
  var points = [(1, 2), (3, 4), (5, 6)];
  for (var (x, y) in points) {
    print('x=$x, y=$y');
  }
}

Key Takeaways

    • Patterns enable destructuring, conditional matching, and variable binding in Dart 3+.
    • Wildcard (_), variable, constant, logical, relational, cast, list, map, record, object, and guard patterns.
    • Patterns are used in switch, if-case, variable declarations, and for loops.
    • Pattern matching makes code more readable and reduces boilerplate.

Try it yourself

void main() {
  var point = (10, 20);
  var (x, y) = point;
  print('x=$x, y=$y');

  var list = [1, 2, 3, 4];
  var [first, ...rest] = list;
  print('first=$first, rest=$rest');

  switch (point) {
    case (int a, int b) when a < b:
      print('$a < $b');
    default: print('not matched');
  }
}

Test Your Knowledge

Q1
of 4

Which pattern is used to ignore a value?

A
ignore
B
skip
C
_
D
null
Q2
of 4

What does `case [_, _, ...]` match?

A
A list with exactly two elements
B
A list with at least two elements
C
A list with exactly three elements
D
A list with at most two elements
Q3
of 4

What keyword is used to add an extra condition to a pattern?

A
if
B
when
C
where
D
guard
Q4
of 4

In which contexts can patterns be used?

A
Only in switch statements
B
Only in variable declarations
C
In variable declarations, switch statements/expressions, if-case, and for loops
D
Only in function parameters

Frequently Asked Questions

Are patterns available in all Dart versions?

No, patterns were introduced in Dart 3.0. You need Dart 3.0 or later to use them.

What is the difference between `if-case` and a regular `if` with a cast?

if-case combines a type check, extraction, and variable binding in a single step. It is more concise and safe than separate is check and cast.

Can I use patterns in `switch` expressions?

Yes, switch expressions (introduced in Dart 3.0) also support patterns, allowing you to return a value based on a pattern match.

What happens if a pattern fails to match in a variable declaration?

If you use var (x, y) = something and the pattern doesn't match (e.g., the value is not a record of two elements), it throws a runtime error. Use if-case or a switch to handle mismatches gracefully.

Can I use custom equality with constant patterns?

Constant patterns use == for comparison. If you have a custom class, ensure it overrides == and hashCode appropriately.

Previous

dart records

Next

dart extension types

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.