控制流语句

优质
小牛编辑
125浏览
2023-12-01

你可以在 Dart 中使用下面任意方式控制代码的执行流程:

  • ifelse
  • for 循环
  • whiledo-while 循环
  • breakcontinue
  • switchcase
  • 断言

你也可以使用 try-catchthrow 控制流程, 如 异常 中所述。

If 和 else

Dart 支持带 else 语句的 if 语句,如下面例子所展示的。另见 条件表达式。

if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}

不像 JavaScript,条件必须使用布尔值,而不是其他的。要了解更多内容,请参阅 For 循环

你可以使用标准的 for 循环进行迭代。比如:

var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
  message.write('!');
}

Dart for 循环中的闭包会捕获 index 的,避免 JavaScript 中常见的一个坑。比如,考虑:

var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());

输出是 0 然后是 1,如期望一样。对比下来,在 JavaScript 中上面的例子会输出 22

如果你要迭代的对象是一个 Iterable,你可以使用 forEach() 方法。如果你不需要知道当前迭代的计数,使用 forEach() 是一个不错的选择。

candidates.forEach((candidate) => candidate.interview());

像列表和集合这样的 Iterable 也支持 for-in 形式的 迭代

var collection = [0, 1, 2];
for (var x in collection) {
  print(x); // 0 1 2
}

While 和 do-while 循环

While 循环在循环之前计算条件:

while (!isDone()) {
  doSomething();
}

do-while 循环在循环后计算条件:

do {
  printLine();
} while (!atEndOfPage());

Break 和 continue

使用 break 中止循环:

while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}

使用 continue 跳到下一个循环:

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}

如果你在用 Iterable,比如列表或者集合,你可能会以不同的方式编写上面的例子:

candidates
    .where((c) => c.yearsExperience >= 5)
    .forEach((c) => c.interview());

Switch 和 case

Dart 中的 switch 语句使用 == 比较整数、字符串或其他编译期常量。被比较的对象必须全部是相同的类的实例(而不是它的任何子类),而且该类必须不能重载 ==枚举类switch 语句中可以良好地运行。

说明:Dart 中的 switch 语句只适用于有限的情况,就像翻译员和扫描仪。

作为规定,每一个非空的 case 子句都以 break 结束。结束一个非空 case 子句的其他方式是 continuethrow 或者 return 语句。

在没有条件匹配的情况下,使用 default 字句执行代码:

var command = 'OPEN';
switch (command) {
  case 'CLOSED':
    executeClosed();
    break;
  case 'PENDING':
    executePending();
    break;
  case 'APPROVED':
    executeApproved();
    break;
  case 'DENIED':
    executeDenied();
    break;
  case 'OPEN':
    executeOpen();
    break;
  default:
    executeUnknown();
}

下面的例子遗漏了 case 子句中的 break,这会产生一个错误:

var command = 'OPEN';
switch (command) {
  case 'OPEN':
    executeOpen();
    // 错误:缺少 break

  case 'CLOSED':
    executeClosed();
    break;
}

然而,Dart 确实支持空的 case 子句,来允许 fall-through 形式:

var command = 'CLOSED';
switch (command) {
  case 'CLOSED': // 空子句 fall-through
  case 'NOW_CLOSED':
    // CLOSED 和 NOW_CLOSED 都会执行
    executeNowClosed();
    break;
}

如果你真的想 fall-through,你可以使用 continue 语句并加上一个标签:

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
  // 在 nowClosed 标签处继续执行

  nowClosed:
  case 'NOW_CLOSED':
    // CLOSED 和 NOW_CLOSED 都会执行
    executeNowClosed();
    break;
}

一个 case 子句可以有局部变量,这些变量仅在该子句中可见。

断言

在开发时,如果一个布尔值为 false,使用 断言 语句——assert(condition, optionalMessage)——来中止正常的执行。你可以在本教程中找到断言语句的例子。下面就是一些:

// 确保变量是非空的值
assert(text != null);

// 确保变量小于100
assert(number < 100);

// 确保变量是一个 https 的 URL
assert(urlString.startsWith('https'));

要添加信息到一个断言,使用一个字符串作为 assert 的第二个参数。

assert(urlString.startsWith('https'),
    'URL ($urlString) should start with "https".');

传递给 assert 的第一个参数只能是可解析为布尔值的表达式。如果这个表达式的值是 true,断言成功并且继续执行。如果它是 false,断言失败并且抛出一个异常(一个 AssertionError)。

断言到底何时起作用?这取决于你所使用的工具和框架:

  • Flutter 在调试模式下启动断言。
  • 开发专用工具像是 dartdevc 通常默认支持断言。
  • 还有一些工具,像是 dartdart2js,通过命令行标志来支持断言:--enable-asserts

在生产环境的代码中,断言会被忽略,而且 assert 的参数也不会被求值。