现在位置: 首页 > Dart 教程 > 正文

Dart 控制流

控制流决定了程序中的代码按照什么顺序执行。

本章介绍 Dart 中的条件判断(if/else、switch)和循环语句(for、while),以及 break 与 continue 的使用。


if / else / else if 条件判断

if 语句是最基本的控制流结构,它根据条件决定是否执行某段代码。

实例

基本的 if 判断:

void main() {
  int score = 85;

  // 基本 if:条件为 true 时执行
  if (score >= 60) {
    print('RUNOOB 恭喜,你及格了!');
  }

  // if-else:二选一
  if (score >= 90) {
    print('优秀');
  } else {
    print('继续加油');
  }

  // if-else if-else:多分支选择
  if (score >= 90) {
    print('等级:A');
  } else if (score >= 80) {
    print('等级:B');
  } else if (score >= 70) {
    print('等级:C');
  } else if (score >= 60) {
    print('等级:D');
  } else {
    print('等级:F(不及格)');
  }
}
RUNOOB 恭喜,你及格了!
继续加油
等级:B

Dart 的条件表达式必须是 bool 类型。不能像 JavaScript 那样用 0、''、null 等作为条件——这些写法在 Dart 中会直接报编译错误。

if 语句的嵌套

if 语句内部可以再嵌套 if,处理更复杂的逻辑。

实例

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

  if (isLoggedIn) {
    // 外层判断:是否登录
    if (isAdmin) {
      // 内层判断:是否是管理员
      print('欢迎回来,管理员 $username');
    } else {
      print('欢迎回来,$username');
    }
  } else {
    print('请先登录');
  }
}
欢迎回来,runoob

嵌套层次过多会降低可读性,建议不超过 3 层。

如果逻辑确实复杂,可以考虑用提前返回(return)或拆分函数来简化。

实例

用提前返回替代深层嵌套:

// 用提前返回替代深层嵌套,可读性更好
String getAccessMessage(bool isLoggedIn, bool isAdmin, String name) {
  // 先处理"不满足条件就返回"的情况
  if (!isLoggedIn) {
    return '请先登录';
  }

  if (!isAdmin) {
    return '你没有管理权限';
  }

  // 最后才是主逻辑
  return '欢迎回来,管理员 $name';
}

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

switch / case 多分支选择

当一个变量有多个固定的可能值时,switch 比 if-else if 更清晰。

实例

void main() {
  String day = '星期三';

  switch (day) {
    case '星期一':
      print('新的一周开始了');
      break;  // break 结束当前 case,防止"穿透"到下一个 case
    case '星期二':
      print('第二天的奋斗');
      break;
    case '星期三':
      print('一周过半了');
      break;
    case '星期四':
      print('快到周五了');
      break;
    case '星期五':
      print('TGIF!');
      break;
    case '星期六':
    case '星期日':
      // 多个 case 可以共用一段代码
      print('周末愉快!');
      break;
    default:
      // 所有 case 都不匹配时执行
      print('未知的日期');
  }
}
一周过半了

Dart 的 switch 不会自动"穿透"(fall-through),每个非空的 case 必须以 break、return、throw 或 continue 结尾。如果想实现穿透效果,使用 continue 配合标签(label)。

switch 表达式(Dart 3.0+)

Dart 3.0 引入了 switch 表达式,可以直接产出值,写法更简洁。

实例

void main() {
  String day = '星期三';

  // switch 表达式:直接返回值
  String mood = switch (day) {
    '星期一' => '有点困',
    '星期二' => '开始适应',
    '星期三' => '干劲十足',
    '星期四' => '期待周末',
    '星期五' => '心情愉悦',
    '星期六' || '星期日' => '自由自在',
    _ => '未知'  // _ 是通配符,相当于 default
  };

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

switch 表达式要求覆盖所有可能的情况,编译器会帮你检查是否有遗漏。


for 循环

for 循环是最常用的循环结构,适合在知道循环次数时使用。

标准 for 循环

实例

void main() {
  // 标准 for 循环:初始化; 条件; 更新
  for (int i = 1; i <= 5; i++) {
    print('RUNOOB 第 $i 次循环');
  }

  // 循环变量也可以在外部声明
  int j = 0;
  for (; j < 3; j++) {
    print('j = $j');
  }
}
RUNOOB 第 1 次循环
RUNOOB 第 2 次循环
RUNOOB 第 3 次循环
RUNOOB 第 4 次循环
RUNOOB 第 5 次循环
j = 0
j = 1
j = 2

for-in 循环(遍历集合)

for-in 是遍历 List、Set 等集合最简洁的方式。

实例

void main() {
  List&lt;String&gt; fruits = ['苹果', '香蕉', '橙子', '葡萄'];

  // for-in:逐个取出集合中的元素
  for (var fruit in fruits) {
    print('RUNOOB 水果: $fruit');
  }
}
RUNOOB 水果: 苹果
RUNOOB 水果: 香蕉
RUNOOB 水果: 橙子
RUNOOB 水果: 葡萄

forEach 方法

List 和 Set 还提供了 forEach 方法,使用回调函数处理每个元素。

实例

void main() {
  List&lt;int&gt; scores = [85, 92, 78, 60];

  // forEach:对每个元素执行回调函数
  scores.forEach((score) {
    String result = score >= 60 ? '及格' : '不及格';
    print('RUNOOB 分数: $score -> $result');
  });
}
RUNOOB 分数: 85 -> 及格
RUNOOB 分数: 92 -> 及格
RUNOOB 分数: 78 -> 及格
RUNOOB 分数: 60 -> 及格

while 与 do-while 循环

while 循环在每次迭代前检查条件,适合循环次数不确定的场景。

实例

void main() {
  // while:先判断条件,再执行
  int count = 3;
  while (count > 0) {
    print('RUNOOB 倒计时: $count');
    count--;  // 记得更新条件变量,否则会死循环
  }
  print('发射!');
}
RUNOOB 倒计时: 3
RUNOOB 倒计时: 2
RUNOOB 倒计时: 1
发射!

do-while 与 while 的区别是:它至少会执行一次循环体,因为条件在最后才检查。

实例

void main() {
  // do-while:先执行一次,再判断条件
  int num = 0;
  do {
    print('RUNOOB 至少执行一次,num = $num');
    num++;
  } while (num < 0);  // 条件一开始就是 false

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

do-while 保证循环体至少执行一次,即使条件一开始就不满足。这在"先尝试再判断"的场景中很有用,比如读取用户输入直到有效。

while vs for:如何选择

场景推荐循环原因
循环次数确定for初始化、条件、更新写在一起,一目了然
循环次数不确定while只关注条件,更灵活
至少执行一次do-while先执行再判断
遍历集合for-in 或 forEach最简洁的集合遍历方式

break 与 continue

break 用于立即退出整个循环,continue 用于跳过当前迭代进入下一轮。

实例

void main() {
  // break:找到目标后立即停止循环
  List&lt;String&gt; names = ['Alice', 'Bob', 'runoob', 'David'];

  for (var name in names) {
    print('检查: $name');
    if (name == 'runoob') {
      print('找到 RUNOOB 了!');
      break;  // 退出循环,不再检查后面的元素
    }
  }

  print('---分隔线---');

  // continue:跳过当前迭代
  for (int i = 1; i <= 5; i++) {
    if (i == 3) {
      continue;  // 跳过 i=3 这次迭代
    }
    print('RUNOOB 第 $i 次');
  }
}
检查: Alice
检查: Bob
检查: runoob
找到 RUNOOB 了!
---分隔线---
RUNOOB 第 1 次
RUNOOB 第 2 次
RUNOOB 第 4 次
RUNOOB 第 5 次

带标签的 break 与 continue

在嵌套循环中,标签可以让你跳出指定的外层循环。

实例

void main() {
  // 标签 outerLoop 标记外层循环
  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('找到目标,退出外层循环');
        break outerLoop;  // 跳出标记为 outerLoop 的外层循环
      }
    }
  }
  print('循环结束');
}
i=1, j=1
i=1, j=2
i=1, j=3
i=2, j=1
i=2, j=2
找到目标,退出外层循环
循环结束

标签(label)应该谨慎使用。大多数情况下,将嵌套循环逻辑提取为独立的函数,用 return 来退出会更清晰。