Dart 控制流
控制流决定了程序中的代码按照什么顺序执行。
本章介绍 Dart 中的条件判断(if/else、switch)和循环语句(for、while),以及 break 与 continue 的使用。
if / else / else if 条件判断
if 语句是最基本的控制流结构,它根据条件决定是否执行某段代码。
实例
基本的 if 判断:
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,处理更复杂的逻辑。
实例
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 更清晰。
实例
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 表达式,可以直接产出值,写法更简洁。
实例
String day = '星期三';
// switch 表达式:直接返回值
String mood = switch (day) {
'星期一' => '有点困',
'星期二' => '开始适应',
'星期三' => '干劲十足',
'星期四' => '期待周末',
'星期五' => '心情愉悦',
'星期六' || '星期日' => '自由自在',
_ => '未知' // _ 是通配符,相当于 default
};
print('RUNOOB 心情: $mood');
}
RUNOOB 心情: 干劲十足
switch 表达式要求覆盖所有可能的情况,编译器会帮你检查是否有遗漏。
for 循环
for 循环是最常用的循环结构,适合在知道循环次数时使用。
标准 for 循环
实例
// 标准 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 等集合最简洁的方式。
实例
List<String> fruits = ['苹果', '香蕉', '橙子', '葡萄'];
// for-in:逐个取出集合中的元素
for (var fruit in fruits) {
print('RUNOOB 水果: $fruit');
}
}
RUNOOB 水果: 苹果 RUNOOB 水果: 香蕉 RUNOOB 水果: 橙子 RUNOOB 水果: 葡萄
forEach 方法
List 和 Set 还提供了 forEach 方法,使用回调函数处理每个元素。
实例
List<int> 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 循环在每次迭代前检查条件,适合循环次数不确定的场景。
实例
// while:先判断条件,再执行
int count = 3;
while (count > 0) {
print('RUNOOB 倒计时: $count');
count--; // 记得更新条件变量,否则会死循环
}
print('发射!');
}
RUNOOB 倒计时: 3 RUNOOB 倒计时: 2 RUNOOB 倒计时: 1 发射!
do-while 与 while 的区别是:它至少会执行一次循环体,因为条件在最后才检查。
实例
// 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 用于跳过当前迭代进入下一轮。
实例
// break:找到目标后立即停止循环
List<String> 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
在嵌套循环中,标签可以让你跳出指定的外层循环。
实例
// 标签 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 来退出会更清晰。
