Dart控制流
流程控制语句 if and else , for, while and do-while , break and continue ,switch语句和表达式
循环
For loops
您可以使用标准for
循环进行迭代。例如:
1
2
3
4
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
Dartfor
循环内的闭包会捕获索引的 值 。这避免了 JavaScript 中常见的陷阱。例如,考虑:
1
2
3
4
5
6
7
8
var callbacks = [];
for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
for (final c in callbacks) {
c();
}
正如预期的那样,输出是 0,然后是 1。相反,该示例将在 JavaScript 中打印 2,然后打印 2。
有时,在迭代Iterable
类型(例如 List 或 Set)时,可能不需要知道当前迭代计数器。在这种情况下,使用 for-in 循环来获得更简洁的代码:
1
2
3
for (final candidate in candidates) {
candidate.interview();
}
要处理从 iterable 获取的值,还可以在 for-in 循环中使用模式 pattern
:
1
2
3
for (final Candidate(:name, :yearsExperience) in candidates) {
print('$name has $yearsExperience of experience.');
}
可迭代类还有一个 forEach()
方法作为另一个选项:
1
2
var collection = [1, 2, 3];
collection.forEach(print); // 1 2 3
While and do-while
while 循环判断循环之前的条件:
1
2
3
while (!isDone()) {
doSomething();
}
do-while
循环判断循环后的条件
1
2
3
do {
printLine();
} while (!atEndOfPage());
Break and continue
使用break
来停止循环:
1
2
3
4
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
使用 continue
跳到下一个循环迭代:
1
2
3
4
5
6
7
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
如果您使用的是 Iterable
(例如列表或集合),则编写前面示例的方式可能会有所不同:
1
2
3
candidates
.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());
分支
If
Dart 支持if
带有可选else
子句的语句。后面括号中的条件必须是计算结果为布尔值的表达式
1
2
3
4
5
6
7
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
If-case
Dart if
语句支持 case
子句后跟一个pattern
1
if (pair case [int x, int y]) return Point(x, y);
如果模式与值匹配,则分支将使用模式在范围内定义的任何变量执行。
在前面的例子中,列表模式[int x, int y]
与值pair
匹配,因此分支返回 Point(x, y)
使用pattern
定义的变量x
和y
。
否则,控制流将前进到else
要执行的分支(如果有):
1
2
3
4
5
if (pair case [int x, int y]) {
print('Was coordinate array $x,$y');
} else {
throw FormatException('Invalid coordinates.');
}
if-case
语句提供了一种针对 单一 模式进行匹配和解构的方法。要针对 多种 模式测试某个值,请使用switch
。
Switch
语句switch
根据一系列case选择值表达式。每个case
语句都是要匹配值的模式。您可以对case使用任何类型的模式。
当值与 case 的模式匹配时,case 主体将执行。非空case
子句在完成后跳转到 switch 的末尾。它们不需要break
语句。结束非空case
子句的其他有效方式是 continue
、throw
或return
语句。
当没有子句匹配时,使用default
或通配符_
子句来执行代码case
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
case 'PENDING':
executePending();
case 'APPROVED':
executeApproved();
case 'DENIED':
executeDenied();
case 'OPEN':
executeOpen();
default:
executeUnknown();
}
空case会直接跳转到下一个case,从而允许case共享一个主体。对于不会直接跳转的空case,使用break
其主体。对于非连续直接跳转,可以使用continue
语句和标签:
1
2
3
4
5
6
7
8
9
10
11
12
13
switch (command) {
case 'OPEN':
executeOpen();
continue newCase; // Continues executing at the newCase label.
case 'DENIED': // Empty case falls through.
case 'CLOSED':
executeClosed(); // Runs for both DENIED and CLOSED,
newCase:
case 'PENDING':
executeNowClosed(); // Runs for both OPEN and PENDING.
}
Switch 表达式
switch
表达式根据匹配的 case 主体生成值。 可以在 Dart 允许表达式的任何地方使用 switch 表达式,但表达式语句的开头除外。例如:
1
2
3
4
5
var x = switch (y) { ... };
print(switch (x) { ... });
return switch (x) { ... };
如果要在表达式语句的开头使用 switch,使用switch 语句。
Switch
表达式允许你重写 switch
语句,如下所示:
1
2
3
4
5
6
7
8
9
10
11
// Where slash, star, comma, semicolon, etc., are constant variables...
switch (charCode) {
case slash || star || plus || minus: // Logical-or pattern
token = operator(charCode);
case comma || semicolon: // Logical-or pattern
token = punctuation(charCode);
case >= digit0 && <= digit9: // Relational and logical-and patterns
token = number();
default:
throw FormatException('Invalid');
}
变成这样的 表达式:
1
2
3
4
5
6
token = switch (charCode) {
slash || star || plus || minus => operator(charCode),
comma || semicolon => punctuation(charCode),
>= digit0 && <= digit9 => number(),
_ => throw FormatException('Invalid')
};
switch
表达式的语法与switch
语句的语法不同:
- Case不以 case 关键字开头。
- Case主体是单个表达式而不是一系列语句。
- 每个Case必须有一个主体;对于空的情况没有隐式的失败。
- 使用 => 而不是 : 将Case模式与其主体分开。
- Case由 , 分隔(并且允许使用可选的尾随 , )
- 默认情况下只能使用
_
,而不是同时允许default
和_
详尽性检查 Exhaustiveness checking
详尽性检查是一项功能,如果某个值有可能进入 switch 但不符合任何情况,则会报告编译时错误。
1
2
3
4
5
6
7
// Non-exhaustive switch on bool?, missing case to match null possibility:
switch (nullableBool) {
case true:
print('yes');
case false:
print('no');
}
默认情况(default
或_
)涵盖了可以流经 switch 的所有可能值。这使得任何类型的 switch 都具有详尽性。
枚举和sealed
类型对于切换尤其有用,因为即使没有默认值,它们的可能值也是已知的并且完全可枚举。在切换该类的子类型时,使用类上的sealed
修饰符可以启用详尽性检查:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sealed class Shape {}
class Square implements Shape {
final double length;
Square(this.length);
}
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
double calculateArea(Shape shape) => switch (shape) {
Square(length: var l) => l * l,
Circle(radius: var r) => math.pi * r * r
};
如果有人要添加 的新子类Shape
,则此switch
表达式将不完整。 详尽性检查会告知您缺少的子类型。 这允许您以某种 函数式代数数据类型样式使用 Dart 。
保护条款 Guard clause
要在子句后设置可选的保护子句case
,请使用关键字when
。保护子句可以跟在if case
、 以及switch
语句和表达式之后。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Switch statement:
switch (something) {
case somePattern when some || boolean || expression:
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause.
body;
}
// Switch expression:
var value = switch (something) {
somePattern when some || boolean || expression => body,
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause.
}
// If-case statement:
if (something case somePattern when some || boolean || expression) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause.
body;
}
匹配后,保护条款会评估任意布尔表达式。这允许您对是否应执行案例主体添加进一步的约束。当保护子句评估为 false 时,执行将继续执行下一个案例,而不是退出整个 switch。