流控制语句定义了 Dart 中的主要语法,语句通常使用一或多个关键字来完成给定任务。语句可以很简单,例如通知函数退出,也可以很复杂,例如指定重复执行某个命令。
本文将对流控制语句和函数进行详细讲解。
流控制语句
if 语句
所有编程语言中最为常用的一个语句就是 if
语句,以下是 if
语句的语法:
if (condition) statement1 else statement2
其中 condition
可以是任意表达式,这个表达式求值的结果必须是布尔值,这点和 JavaScript、PHP 的要求不同,在 JavaScript、PHP 中,表达式求值的结果即使不是布尔值,脚本引擎执行代码时也会在底层隐式转换为布尔值。
statement1
和 statement2
既可以是一行代码,也可以是一个代码块(以一对花括号括起来的多行代码):
void main() {
if (2 > 1)
print('2 大于 1');// output: 2 大于 1
else {
print('2 小于 1');
}
}
业界普遍推崇的最佳实践是始终使用代码块,即使要执行的只有一行代码,因为这样可以消除人们的误解,否则可能让人分不清在不同条件下要执行哪些语句。
void main() {
if (2 > 1) {
print('2 大于 1');// output: 2 大于 1
} else {
print('2 小于 1');
}
}
do-while 语句
do-while
语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。换句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次。需要注意的是条件表达式和 if 语句的语法一样,只能是布尔值,以下是 do-while
语句的语法:
do {
statement
} while (expression);
下面是一个例子:
void main() {
int i = 0;
do {
i += 2;
print(i);
} while(i < 10);
}
// output: 2 4 6 8 10
while 语句
while
属于前测试循环语句,也就是说,在循环体内的代码被执行之前,就会对出口条件求值。
void main() {
int i = 10;
while(i > 0) {
print(--i);
}
}
// output: 9 8 7 6 5 4 3 2 1 0
for 语句
for
语句也是一种前测试循环语句,但是它必须在执行循环之前初始化变量以及定义循环后要执行的代码。
void main() {
for (int i = 0; i < 10; i++) {
print(i);
}
}
// output: 0 1 2 3 4 5 6 7 8 9
break 和 continue 语句
break
和 continue
语句用于在循环中精确地控制代码的执行。其中,break
语句会立刻退出循环,强制继续执行循环外的语句,而 continue
语句虽然也是立即退出循环,但退出循环后会从循环的顶部继续执行,以下是关于 break
的例子:
void main() {
int i = 10;
while (i > 0) {
--i;
if (i & 1 == 0) break;
print(i);
}
print('is over');
}
// output: 9 is over
上面的代码中能够被 2 整除,就会立刻停止循环,下面是关于 continue
的例子,下面的代码只会打印奇数:
void main() {
int i = 10;
while (i > 0) {
--i;
if (i & 1 == 0) continue;
print(i);
}
print('is over');
}
// output: 9 7 5 3 1 is over
switch 语句
switch
语句与 if
语句的关系最为密切,而且也是在其他语言中普遍使用的一种流控制语句,下面是使用示例:
void main() {
String i = 'A';
String state;
switch (i) {
case 'S':
state = '学神';
break;
case 'A':
state = '学霸';
break;
case 'B':
state = '学混';
break;
default:
state = '学渣';
}
print(state);// output: 学霸
}
assert 语句
assert
顾名思义,即断言,使用格式为 assert(condition)
,当 condition
的求值为 false
时程序将终止执行。例如:
void main() {
print('start');
assert(1 < 0);
print('over');
}
// output: start
// Unhandled exception:
// Failed assertion: line 23 pos 10: '1 < 0': is not true.
以上代码只会输出 start
,并且在调试环境中将会报错。
函数
函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。函数的基本语法如下所示:
sum(num1, num2) {
return num1 + num2;
}
上面的代码中定义了一个 sum
函数,需要传入两个参数:num1
和 num2
,参数的类型都是 int
。
Dart 最佳实践 中推荐为函数体规定类型,所以下面的代码中,我们可以规定为 int
:
int sum(int num1, int num2) {
return num1 + num2;
}
对于只有一个表达式的函数,我们可以使用胖箭头语法来进行缩写,这和 ECMAScript 6 的箭头函数语法很相似,并且 Dart 最佳实践 推荐箭头函数省略类型,所以最终换成如下写法:
sum(num1, num2) => num1 + num2;
参数
函数可以有两种类型的参数:必需参数 和 可选参数,必需参数在参数列表的前面,可选参数在必需参数的后面。
可选参数也有两种方式定义:可选命名 和 可选位置。
可选命名参数使用 {param1, param2, …}
的形式来指定命名参数:
sum({num1, num2}) => num1 + num2;
可选位置参数将参数放到 []
即可:
sum(num1, num2, [num3]) => num1 + num2;
参数默认值
在定义函数时,可以使用 =
来定义参数的默认值,如果没有定义默认值,则默认值为 null
。
设置可选命名参数的默认值:
sum({num1 = 1, num2 = 2}) => num1 + num2;
设置可选位置参数的默认值:
sum(num1, num2, [num3 = 3, num4]) => num1 + num2;
The main() function(入口函数)
每个应用都需要有个顶级的 main()
入口函数才能执行。 main()
函数的返回值为 void
,并且有个可选的 List<String>
参数。
所以如果需要调用 sum
函数,在 main
中调用即可:
sum({num1 = 1, num2 = 2}) => num1 + num2;
main() {
final foo = sum();
final bar = sum(num1: 123, num2: 456);
print(foo);// output: 3
print(bar);// output: 579
}
下面的例子中,main
函数使用了方法参数作为输入参数:
main(List<String> arguments) => print(arguments);
// output: []
一等函数对象
函数本身就是一个对象,所以可以作为参数传入另外一个方法:
int batchIncrement(int num) => ++num;
void main() {
var numberList = [1, 2, 3];
final numberListBig = numberList.map(batchIncrement);
print(numberListBig);// output: (2, 3, 4)
}
anonymous function(匿名函数)
创建一个没有名字的函数,并将它赋值给一个变量,这种情况下创建的函数叫做匿名函数(也称作拉姆达函数),用法示例:
Function canonical = (String str) => print(str.toUpperCase());
main() => canonical('php');// output: PHP
下面的代码中将一个参数为 i
的匿名函数传递给了 map
方法:
void main() {
var fruits = ['banana', 'cucumber', 'eggplant'];
final fruitsIndex = fruits.map((i) => '${fruits.indexOf(i)} : $i');
print(fruitsIndex);// output: (0 : banana, 1 : cucumber, 2 : eggplant)
}
静态作用域
Dart 是静态作用域语言,也就是说大括号内的变量只能在大括号中访问,这一点和 PHP、JAVA 相同,ECMAScript 6 也利用 let
、const
关键字实现了这个功能。
下面这个例子中,在 nestedFunction
内可以访问外层的所有变量:
const topLevel = true;
void main() {
const insideMain = true;
void myFunction() {
const insideFunction = true;
void nestedFunction() {
const insideNestedFunction = true;
print(insideNestedFunction);// output: true
print(insideFunction);// output: true
print(insideMain);// output: true
print(topLevel);// output: true
}
nestedFunction();
}
myFunction();
}
返回值
所有函数都有一个返回值,如果没有指定返回值,则默认把语句 return null
作为函数的最后一个语句执行。
