Dart Control Flow

Control flow determines the order in which code in a program executes.

This chapter introduces conditional judgments (if/else, switch) and loop statements (for, while) in Dart, as well as the use of break and continue.


if / else / else if Conditional Statements

The if statement is the most basic control flow structure; it decides whether to execute a piece of code based on a condition.

Example

Basic if statements:

void main() {
  int score = 85;

  // Basic if: executes when condition is true
  if (score >= 60) {
    print(EXAMPLE, congratulations, you passed!);
  }

  // if-else: choose one of two
  if (score >= 90) {
    print('Excellent');
  } else {
    print(Keep it up!);
  }

  // if-else if-else: multi-branch selection
  if (score >= 90) {
    print(Grade: A);
  } else if (score >= 80) {
    print(Grade: B);
  } else if (score >= 70) {
    print(Grade: C);
  } else if (score >= 60) {
    print(Grade: D);
  } else {
    print(Grade: F (fail));
  }
}
EXAMPLE 恭喜,你及格了!
继续加油
等级:B

In Dart, conditional expressions must be of type bool. You cannot use 0, '', null, etc. as conditions like in JavaScript—these will directly cause compilation errors in Dart.

Nested if statements

if statements can be nested inside each other to handle more complex logic.

Example

void main() {
  bool isLoggedIn = true;
  bool isAdmin = false;
  String username = 'example';

  if (isLoggedIn) {
    // Outer check: whether logged in
    if (isAdmin) {
      // Inner check: whether admin
      print(Welcome back, admin $username);
    } else {
      print(Welcome back, $username);
    }
  } else {
    print(Please log in first);
  }
}
欢迎回来,example

Too many nesting levels can reduce readability; it is recommended not to exceed 3 levels.

If the logic is truly complex, consider using early returns or splitting functions to simplify.

Example

Replacing deep nesting with early returns:

// Use early return instead of deep nesting for better readability
String getAccessMessage(bool isLoggedIn, bool isAdmin, String name) {
  // First handle the 'return if condition not met' case
  if (!isLoggedIn) {
    return Please log in first;
  }

  if (!isAdmin) {
    return 'You do not have admin permissions';
  }

  // Finally, the main logic
  return 'Welcome back, admin $name';
}

void main() {
  print(getAccessMessage(true, false, 'example'));
  print(getAccessMessage(true, true, 'example'));
}
你没有管理权限
欢迎回来,管理员 example

switch / case multi-branch selection

When a variable has multiple fixed possible values, switch is clearer than if-else if.

Example

void main() {
  String day = 'Wednesday';

  switch (day) {
    case 'Monday':
      print('A new week has started');
      break;  // break ends the current case, preventing 'fall-through' to the next case
    case 'Tuesday':
      print('The second day of hard work');
      break;
    case 'Wednesday':
      print('Halfway through the week');
      break;
    case 'Thursday':
      print('Almost Friday');
      break;
    case 'Friday':
      print('TGIF!');
      break;
    case 'Saturday':
    case 'Sunday':
      // Multiple cases can share one block of code
      print('Happy weekend!');
      break;
    default:
      // Runs when no case matches
      print('Unknown date');
  }
}
The week is half over.

Dart's switch does not automatically "fall through"; every non-empty case must end with break, return, throw, or continue. If you want to achieve a fall-through effect, use continue with a label.

switch expression (Dart 3.0+)

Dart 3.0 introduced switch expressions, which can directly produce values, making the syntax more concise.

Example

void main() {
  String day = 'Wednesday';

  // switch expression: directly returns a value
  String mood = switch (day) {
    'Monday' => 'A little sleepy',
    'Tuesday' => 'Starting to adapt',
    'Wednesday' => 'Full of energy',
    'Thursday' => 'Looking forward to the weekend',
    'Friday' => 'In a cheerful mood',
    'Saturday' || 'Sunday' => 'Carefree',
    _ => 'Unknown'  // _ is a wildcard, equivalent to default
  };

  print('EXAMPLE mood: $mood');
}
EXAMPLE 心情: 干劲十足

switch expressions require covering all possible cases; the compiler will help you check for omissions.


for Loop

The for loop is the most common loop structure, suitable when you know the number of iterations.

Standard for loop

Example

void main() {
  // Standard for loop: initialization; condition; update
  for (int i = 1; i <= 5; i++) {
    print('EXAMPLE loop $i');
  }

  // The loop variable can also be declared outside
  int j = 0;
  for (; j < 3; j++) {
    print('j = $j');
  }
}
EXAMPLE 第 1 次循环
EXAMPLE 第 2 次循环
EXAMPLE 第 3 次循环
EXAMPLE 第 4 次循环
EXAMPLE 第 5 次循环
j = 0
j = 1
j = 2

for-in loop (traversing collections)

for-in is the simplest way to iterate over collections like List and Set.

Example

void main() {
  List<String> fruits = [Apple, Banana, Orange, 'Grape'];

  // for-in: iterates over the elements in the collection one by one
  for (var fruit in fruits) {
    print(EXAMPLE Fruit: $fruit);
  }
}
EXAMPLE 水果: 苹果
EXAMPLE 水果: 香蕉
EXAMPLE 水果: 橙子
EXAMPLE 水果: 葡萄

forEach method

List and Set also provide the forEach method, which uses a callback function to process each element.

Example

void main() {
  List<int> scores = [85, 92, 78, 60];

  // forEach: execute the callback function for each element
  scores.forEach((score) {
    String result = score >= 60 ? 'Pass' : 'Fail';
    print(EXAMPLE Score: $score -> $result);
  });
}
EXAMPLE 分数: 85 -> 及格
EXAMPLE 分数: 92 -> 及格
EXAMPLE 分数: 78 -> 及格
EXAMPLE 分数: 60 -> 及格

while and do-while loops

The while loop checks the condition before each iteration, suitable for scenarios where the number of iterations is uncertain.

Example

void main() {
  // while: check the condition first, then execute
  int count = 3;
  while (count > 0) {
    print(EXAMPLE Countdown: $count);
    count--;  // Remember to update the condition variable, otherwise it will be an infinite loop
  }
  print(Launch!);
}
EXAMPLE 倒计时: 3
EXAMPLE 倒计时: 2
EXAMPLE 倒计时: 1
发射!

The difference between do-while and while is that it executes the loop body at least once, because the condition is checked at the end.

Example

void main() {
  // do-while: execute once first, then check the condition
  int num = 0;
  do {
    print(EXAMPLE executes at least once, num = $num);
    num++;
  } while (num < 0);  // The condition is false from the start

  print(Loop ended, num = $num);
}
EXAMPLE 至少执行一次,num = 0
循环结束,num = 1

The do-while loop guarantees the loop body executes at least once, even if the condition is not met from the start. This is useful in "try first, then evaluate" scenarios, such as reading user input until it is valid.

while vs for: How to choose

ScenariosRecommended loopReason
Determinate Number of IterationsforInitialization, condition, and update written together, clear at a glance
Indeterminate Number of IterationswhileFocus Only on the Condition, More Flexible
Executes at Least Oncedo-whileExecute First, Then Evaluate
Traversing collectionsfor-in or forEachThe most concise way to iterate over collections

break and continue

break is used to immediately exit the entire loop, while continue is used to skip the current iteration and move to the next.

Example

void main() {
  // break: stop the loop immediately after finding the target
  List<String> names = ['Alice', 'Bob', 'example', 'David'];

  for (var name in names) {
    print(Check: $name);
    if (name == 'example') {
      print(Found EXAMPLE!);
      break;  // Exit the loop, no longer checking the following elements
    }
  }

  print(---separator---);

  // continue: skip the current iteration
  for (int i = 1; i <= 5; i++) {
    if (i == 3) {
      continue;  // skip the i=3 iteration
    }
    print('EXAMPLE iteration $i');
  }
}
检查: Alice
检查: Bob
检查: example
找到 EXAMPLE 了!
---分隔线---
EXAMPLE 第 1 次
EXAMPLE 第 2 次
EXAMPLE 第 4 次
EXAMPLE 第 5 次

Labeled break and continue

In nested loops, labels allow you to jump out of a specified outer loop.

Example

void main() {
  // The label outerLoop marks the outer loop
  outerLoop:
  for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++) {
      print('i=$i, j=$j');
      if (i == 2 && j == 2) {
        print('Target found, exit outer loop');
        break outerLoop;  // Break out of the outer loop labeled outerLoop
      }
    }
  }
  print('Loop ended');
}
i=1, j=1
i=1, j=2
i=1, j=3
i=2, j=1
i=2, j=2
找到目标,退出外层循环
循环结束

Labels should be used with caution. In most cases, extracting nested loop logic into independent functions and using return to exit is clearer.

other extensions