💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] >译者注:流程控制在大部分语言中大同小异,在Dart中只有最后一个assert比较特殊,其实assert在前边的章节中也使用过了,如果有其他计算机语言经验的开发者可以直接跳到assert部分去看。 > *** 您可以使用以下任何一种方法来控制Dart代码的流: * if 和 else * for循环 * while和do-while循环 * break和continue * switch和case * assert 你也可以使用try-catch和throw来对控制流程作出改变,如[Exception(异常)]中所说明。 ### if 和 else Dart支持带有可选else语句的if语句,如下面的示例所示。请参阅[条件表达式]。 ~~~ if (isRaining()) { you.bringRainCoat(); } else if (isSnowing()) { you.wearJacket(); } else { car.putTopDown(); } ~~~ 与JavaScript不同的是,条件必须使用布尔值,不允许其他值。有关更多信息,请参见[布尔类型]。 >译者注:以上说明可能不是非常清晰,那我们通过代码示例来说明下。我们知道JavaScript等其他很多语言中0和负数可以表示false而正数表示true但是这在Dart中是行不通的,请看下边的例子: > ~~~ void main() { var a=1; if(a) { print('yes'); }else{ print('error'); } } ~~~ 以上代码看着貌似没任何问题,理想的结果输出为"yes",但是让我们来看看真实的输出结果: ![](https://box.kancloud.cn/baa9bffe0c10f33a687b59f2c4b5498a_2648x344.png) 在执行执行时抛出了异常,异常的意思是int类型不能复制给bool类型。从这儿我们也可以看出Dart中if判断的原理。 *** ### For循环 你可以使用标准for循环进行迭代操作(处理重复的操作),例如: ~~~ var message = StringBuffer('Dart is fun'); for (var i = 0; i < 5; i++) { message.write('!'); } ~~~ Dart for循环内部的闭包捕获了索引的值,避免了JavaScript中常见的陷阱。例如: ~~~ var callbacks = []; for (var i = 0; i < 2; i++) { callbacks.add(() => print(i)); } callbacks.forEach((c) => c()); ~~~ 输出是0,然后是1,正如预期的那样。相反,该示例将在JavaScript中输出2和2。 >译者注:当然如果是JavaScript程序猿应该知晓这个问题,下边我在Chrome的控制台下演示本错误。 > ![](https://box.kancloud.cn/8a2e29ff61684d00f66d45311a422430_429x198.png) 从以上可以看出不同之处。 *** 如果要迭代的对象是可迭代的,那么可以使用forEach()方法。使用forEach()本身是没有迭代计数器的,也就是for循环本身有i值在forEach()本身是没有的。 ~~~ candidates.forEach((candidate) => candidate.interview()); ~~~ 可迭代类如List和Set也支持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()); ~~~ >译者注:所以使用while和do-while要非常小心,因为使用do-while如果条件为假也会至少执行一次循环体中的语句。 > *** ### 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(); } ~~~ 如果你使用的是可迭代的,比如列表或集合,你可能会用不同的方式来写这个例子: ~~~ candidates .where((c) => c.yearsExperience >= 5) .forEach((c) => c.interview()); ~~~ >译者注:对于以上的最后一种写法想必大家还是感觉很难理解,那么我通过示例代码给大家说明下: > ~~~ class A { var yearsExperience; A(int year) { this.yearsExperience = year; } interview() { print(this.yearsExperience); } } void main() { List personList = [ A(1), A(2), A(5), A(6) ]; ///第一种写法 for(int i = 0; i < personList.length; i++) { var person = personList[i]; if (person.yearsExperience < 5) { continue; } person.interview(); } ///第二种写法 personList .where((c) => c.yearsExperience >= 5) .forEach((c) => c.interview()); } ///执行结果 5 6 5 6 ~~~ 两次结果都相同,那么这儿的where()方法究竟是什么呢,我们在后续会接触到,他是dart.core中的iterable.dart中的方法,他返回复合where()中条件的集合视图,所以在where()后边我们可以继续调用forEach(),当然如果where()返回的集合视图为空也不会出现错误,仅仅是forEach()不执行而已。这儿where()的作用类似于过滤器。 *** ### switch 和 case 在Dart中switch语句使用 “==”运算来比较整数,字符串或者编译时常量。被比较对象必须都是同一个类的实例(而不是它的任何子类型),并且这个类不能重写“==”操作。枚举类型在switch语句是一种非常好的应用场景。 >注意:Dart中的Switch语句适用于有限的情况,例如在解释器或扫描器中。 > switch的规则是每个非空的case子句以一个break语句结束。结束非空case子句的其他有效方法是continue、throw或return语句。 当没有case子句匹配时,使用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(); // ERROR: Missing break case 'CLOSED': executeClosed(); break; } ~~~ 然而,Dart支持空的case子句,支持fall-through的格式: ~~~ var command = 'CLOSED'; switch (command) { case 'CLOSED': // Empty case falls through. case 'NOW_CLOSED': // 无论command是CLOSED还是NOW_CLOSED都执行 executeNowClosed(); break; } ~~~ 如果你真的需要使用fall-through格式,你可以使用continue语句和一个标签,例如: ~~~ var command = 'CLOSED'; switch (command) { case 'CLOSED': executeClosed(); continue nowClosed; // Continues executing at the nowClosed label. nowClosed: case 'NOW_CLOSED': // Runs for both CLOSED and NOW_CLOSED. executeNowClosed(); break; } ~~~ case子句可以有局部变量,只能在该子句的范围内可见。 ### Assert (断言) 如果布尔条件为false,则使用assert语句中断正常执行。您可以在本教程中找到assert声明的示例。如下示例: ~~~ // Make sure the variable has a non-null value. assert(text != null); // Make sure the value is less than 100. assert(number < 100); // Make sure this is an https URL. assert(urlString.startsWith('https')); ~~~ >注意:Assert语句不会影响生产环境中代码的执行,它仅仅在测试环境中起作用。在Flutter的调试模式下可以使用assert。默认情况下,像(dartdevc typically)只支持开发环境的工具默认支持assert。例如dart和dart2js通过命令行标记:--enable-asserts来支持asserts。 > 要将提示消息附加到断言,请添加一个字符串作为第二个参数。 ~~~ assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".'); ~~~ 断言的第一个参数可以是任何解析为布尔值的表达式。如果表达式的值为true,则断言成功并继续执行。如果是false,则断言失败,并抛出异常(AssertionError)。