Skip to main content
A guarded pattern in Dart is a construct used exclusively within switch statements and switch expressions that qualifies a pattern match with a boolean predicate. The guard, denoted by the when keyword, requires that the condition evaluate to true for the case to be selected, even if the pattern matches the value’s structure and type.

Syntax

The guard clause immediately follows the pattern and precedes the case body or expression arrow. In a switch statement:
case <pattern> when <boolean_expression>: <body_statements>
In a switch expression:
<pattern> when <boolean_expression> => <expression>,

Evaluation Semantics

The runtime evaluates a guarded pattern in a strict sequence:
  1. Pattern Matching: The subject value is tested against the pattern’s structure and type.
  2. Variable Binding: If the pattern matches, any variables defined within the pattern are destructured and bound.
  3. Guard Evaluation: The boolean expression in the when clause is evaluated.
    • Scope: Variables bound in step 2 are accessible within the guard expression.
  4. Result Determination:
    • If the guard evaluates to true, the match succeeds, and the corresponding body executes.
    • If the guard evaluates to false, the match is refuted. The execution flow proceeds to the next case or default clause.

Valid Contexts

Guarded patterns are supported only in switch contexts. They are not valid in if-case statements, for-case loops, or variable declarations.

Switch Statement

The guard acts as a filter for the case block.
switch (data) {
  // Matches only if data is a list of two integers AND a > b
  case [int a, int b] when a > b:
    handleDescending(a, b);
    
  // Fallback for other lists of two integers
  case [int a, int b]:
    handleAscendingOrEqual(a, b);
}

Switch Expression

Guards allow a single pattern structure to map to different result expressions based on value constraints.
String describe(dynamic value) {
  return switch (value) {
    // Guard checks properties of the matched object
    String s when s.isNotEmpty => 'Non-empty string',
    String _ => 'Empty string',
    int n when n > 0 => 'Positive integer',
    _ => 'Unknown'
  };
}

Refutation and Fallthrough

A guard failure is distinct from a boolean check inside a case body. If a guard evaluates to false, the switch statement does not terminate; instead, it treats the specific case as a non-match and continues evaluating subsequent cases.
switch (number) {
  // If number is 10:
  // 1. Pattern 'int n' matches.
  // 2. Guard '10 > 20' is false.
  // 3. Execution falls through to the next case.
  case int n when n > 20:
    print('Big');
    
  // This case catches the value 10.
  case int n:
    print('Small'); 
}
Master Dart with Deep Grasping Methodology!Learn More