第5章 流程控制语句 在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。控制语句用实现对程序流程的选择、循环、转向和返回等进行控制。只有在清楚每条语句的执行流程的前提下,才能通过控制语句的执行顺序实现要完成的任务。 Dart中的控制语句分为以下几类: (1) 分支语句: if和switch。 (2) 循环语句: while、dowhile和for。 (3) 跳转语句: break、continue、return和throw。 创建命令行应用程序,将项目命名为chapter5。本章所有文件都在该项目的bin文件夹下创建与运行。 5.1分支语句 11min 分支语句又称条件语句,条件语句使得部分程序块根据表达式的值有选择地执行。Dart语言提供了if和switch两种分支语句。 5.1.1if语句 具体来说分支语句由选择结构组成,if语句引导的选择结构包括if结构、ifelse结构和elseif结构。 1. if结构 if结构包含条件表达式和语句块,当条件表达式为true时执行语句块,否则执行if结构后面的语句。通常来说语句块由大括号({})包裹,如果if结构中的语句块只有一条语句,则可以省略大括号。 if结构声明语法如下: if(条件表达式){ //语句块 } 示例代码如下: //chapter5/bin/example_01.dart void main(){ var x = true,y = 10; if(x){ //此处x为真,语句体得到执行 print('条件x为$x'); } if(!x){ //此处!x为假,语句体得不到执行 print('条件!x为$x,if语句体得到执行。'); } //此处省略大括号 if(y<=10) //条件y<=10为真,语句体得到执行 print('条件y<=10为${y<=10}'); } 2. ifelse结构 在if结构中,只有条件表达式为true时提供相应的处理语句块。有时无论条件表达式为true还是false都需进行相应处理,此时可以使用ifelse结构。声明格式如下: if(条件表达式){ //语句块1 }else{ //语句块2 } 当程序执行到if语句时,先判断条件表达式,如果值为true,则执行语句块1,然后跳过else语句块,继续执行后续语句。如果条件表达式值为false,则忽略语句块1直接执行语句块2,然后继续执行后续语句。 ifelse结构使用示例代码如下: //chapter5/bin/example_02.dart void main(){ var x = true; if(!x){ //条件!x为真时,if语句块得到执行 print('if !x:${!x}'); }else{ //条件!x为假时,else语句块得到执行 print('else !x:${!x}'); } } 3. elseif结构 elseif结构是ifelse结构的多层嵌套形式,它会在多个分支中执行一个语句块,其他分支将不会得到执行,所以这种结构常用于有多种判断结果的分支中。 elseif结构如下: if(条件表达式1){ //语句块1 }else if(条件表达式2){ //语句块2 } ... }else if(条件表达式n){ //语句块n }else{ //语句块n+1 } elseif结构使用示例代码如下: //chapter5/bin/example_03.dart void main(){ var x = true,y = 10; if(!x){ //条件!x为假, if语句块不会执行 print('条件x为$x'); }else if(y<=10){ //如果条件y<=10为真,则else if语句块得到执行 print('条件y<=10为${y<=10}'); }else{ //当所有条件都为假时,else语句块才会执行 print('else !x:${!x}。'); } } 5.1.2switch语句 可以使用switch语句选择要执行的多个代码块中的一个代码块,语法如下: switch(expr){ case 值1: //语句块1 break; case 值2: //语句块2 break; ... case 值n: //语句块n break; default: //语句块n+1 } 首先设置表达式expr,通常是一个变量。随后表达式的值会与结构中的每个case的值做比较。如果存在匹配,则与该case子句关联的代码块会被执行。如果case子句中没有与expr匹配的值,则会执行default子句的语句块,然后跳出switch结构。 switch语句使用==来比较整数、字符串或编译时常量,比较的两个对象必须是同一个类的实例且没有覆写==运算符。 每个非空的case子句必须包含一个break语句。当没有匹配的子句时,可以使用default子句匹配这种情况。示例代码如下: //chapter5/bin/example_04.dart void main(){ var color = 'Red'; switch(color){ case 'Green': print('color值为Green'); break; case 'Orange': print('color值为Orange'); break; case 'Red': print('color值为Red'); break; default: print('color值未匹配'); } } 下面的例子忽略了break子句,因此产生错误。 //chapter5/bin/example_05.dart void main(){ var color = 'Red'; switch(color){ case 'Green': print('color值为Green'); //执行出错,没有break语句 case 'Orange': print('color值为Orange'); break; case 'Red': print('color值为Red'); break; default: print('color值未匹配'); } } Dart语言支持case子句的内容为空,这种情况称为贯穿。下例中值为Orange的case子句内容为空,它会造成贯穿。当传入变量值为Orange时,程序会继续执行与它相邻的值为Red的case子句。示例代码如下: //chapter5/bin/example_06.dart void main(){ var color = 'Orange'; switch(color){ case 'Green': print('color值为Green'); break; case 'Orange': //空语句贯穿 case 'Red': //color值为Orange和Red都会被执行 print('color值为Red'); break; default: print('color值未匹配'); } } 非空case子句实现贯穿可以通过continue语句和标签来完成。下例中匹配到值为Green的case子句时,不仅会执行该子句的代码块,还会执行值为Red的case子句中的代码块。示例代码如下: //chapter5/bin/example_07.dart void main(){ var color = 'Green'; switch(color){ case 'Green': print('color值为Green'); //继续执行标签为red的case子句 continue red; case 'Orange': print('color值为Orange'); break; //标签red,它代表了case值为Red的子句 red: case 'Red': //color值为Green和Red都会被执行 print('color值为Red'); break; default: print('color值未匹配'); } } 每个case子句都可以有局部变量且仅在该case子句内有效。 5.2循环语句 9min 循环语句能够根据循环条件使程序代码重复执行。Dart支持3种循环结构: for、while和dowhile。 5.2.1for语句 for语句是一种应用广泛、功能最强的循环语句。声明格式如下: for(表达式1;表达式2;表达式3){ //循环语句块 } 表达式1是初始化语句,用于初始化循环变量和其他变量。表达式2是循环条件,表达式3用于更新循环变量,使循环变量趋近于某个值,直到使循环条件变为false。 开始for循环时,会执行表达式1初始化循环变量,表达式1只会执行一次。然后执行表达式2,判断循环条件是否满足,如果满足,则继续执行循环体。执行完成后继续执行表达式3,更新循环变量,然后接着再判断循环条件。如此反复,直到循环条件不满足时跳出循环。执行流程如图51所示。 for循环使用示例代码如下: //chapter5/bin/example_08.dart void main(){ for (var i = 0;i < 5;i++){ //此处i的初始值为0,所以使用i+1保证其与实际循环次数一致 print('第${i+1}次循环。'); } } 图51for循环执行流程图 循环开始时,给循环变量i赋值为0,每次执行循环体前都会判断i的值是否小于5,如果为true,则执行循环体,然后执行i++,使得循环变量i的值加1。然后继续判断循环条件,直到判断结果为false时跳出循环。 对于实现了iterable接口的类可以使用forEach()函数进行迭代。例如List和Set类,它们还支持forin形式的迭代。示例代码如下: //chapter5/bin/example_09.dart void main(){ var collection = [0, 1, 2]; //这里给forEach函数传入了一个匿名函数 collection.forEach((i)=>print(i)); //for-in形式的迭代 for (var x in collection) { print(x); } } 在Dart语言中,for循环中的闭包会自动捕获索引值,这在某些情况下很有用。示例代码如下: //chapter5/bin/example_10.dart void main(){ var callbacks = []; for (var i = 0; i < 2; i++) { callbacks.add(() => print(i)); } callbacks.forEach((c) => c()); } 5.2.2while语句 while循环在执行循环体前先判断循环条件,如果条件为真则执行循环体,如果条件为假则结束循环。 声明格式如下: while(循环条件){ //语句块 } 在while循环体中一定要存在影响循环条件的语句,其作用是使循环条件最终变为false以避免无限循环。 示例代码如下: //chapter5/bin/example_11.dart void main(){ var i=0,x=10; while(i