Skip to content

分支
本页面介绍如何使用分支控制 Dart 代码的执行流程:

  • if 语句和元素
  • if-case 语句和元素
  • switch 语句和表达式

你还可以通过以下方式操控 Dart 的执行流程:

  • 循环结构(如 forwhile
  • 异常处理(如 trycatchthrow

if 语句

Dart 支持带可选子句的语句。括号内的条件必须是评估为布尔值的表达式:if / else if

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

若要在表达式上下文中使用 if,请参阅条件表达式


if-case 语句

Dart 语句支持后接模式匹配的子句:if / case

dart
if (pair case [int x, int y]) return Point(x, y);

当模式与值匹配时,分支会执行,且模式中定义的变量会进入作用域。

前例中,列表模式 [int x, int y] 匹配了 pair 的值,因此分支执行时会将模式定义的变量 xy 带入作用域,并返回 Point(x, y)

若无匹配,控制流会继续执行后续分支(如果有):else

dart
if (pair case [int x, int y]) {
  print('坐标数组: $x,$y');
} else {
  throw FormatException('无效坐标');
}

if-case 语句提供了一种针对单一模式进行匹配和解构的方式。若需测试多个模式,请使用 switch

版本说明if 语句中的 case 子句需要 Dart 语言版本 ≥ 3.0。


switch 语句

switch 语句将一个值表达式与一系列 case 进行匹配。每个子句是待匹配的模式。switch 支持任意类型的模式。

当值匹配某个 case 的模式时,该分支体执行。非空子句完成后会跳转到 switch 末尾(无需显式 break)。其他合法结束方式包括 continuethrowreturn 语句。

使用 default 或通配符 _ 子句处理无匹配情况:

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

case 会穿透到下一分支(共享执行体)。若需禁止穿透,用 break 作为空分支体。非连续穿透可通过 continue 和标签实现:

dart
switch (command) {
  case 'OPEN':
    executeOpen();
    continue newCase; // 跳转至 newCase 标签

  case 'DENIED': // 空分支穿透
  case 'CLOSED':
    executeClosed(); // 同时处理 DENIED 和 CLOSED

  newCase:
  case 'PENDING':
    executeNowClosed(); // 同时处理 OPEN 和 PENDING
}

逻辑或模式(||)允许多个 case 共享执行体或守卫条件。更多模式与子句用法详见文档

版本说明switch 语句需要 Dart 语言版本 ≥ 3.0。


switch 表达式

switch 表达式根据匹配的 case 返回一个值。它可用于 Dart 允许表达式的任何位置(表达式语句开头除外)。例如:

dart
var x = switch (y) { ... };
print(switch (x) { ... });
return switch (x) { ... };

若需在表达式语句开头使用 switch,请改用 switch 语句。

switch 表达式可重构传统语句为更简洁的形式:

dart
// 传统 switch 语句(使用常量变量 slash/star/comma/semicolon/digit0/digit9...)
switch (charCode) {
  case slash || star || plus || minus: 
    token = operator(charCode);
  case comma || semicolon: 
    token = punctuation(charCode);
  case >= digit0 && <= digit9: 
    token = number();
  default:
    throw FormatException('无效字符');
}

等价于表达式形式:

dart
token = switch (charCode) {
  slash || star || plus || minus => operator(charCode),
  comma || semicolon => punctuation(charCode),
  >= digit0 && <= digit9 => number(),
  _ => throw FormatException('无效字符'),
};

switch 表达式与语句的关键语法差异:

  • case 前无需关键字
  • 分支体是单一表达式而非语句序列
  • 每个 case 必须显式定义分支体(无隐式穿透)
  • 模式与分支体用 => 分隔而非 :
  • 分支间用 , 分隔(允许末尾可选逗号)
  • 默认分支仅支持 =>(不可混合使用 :

版本说明switch 表达式需要 Dart 语言版本 ≥ 3.0。


完备性检查

完备性检查会在编译时报告错误:若存在值可能进入 switch 却不匹配任何 case 的情况。

dart
// 非完备 switch(缺失 null 分支)
switch (nullableBool) {
  case true: print('yes');
  case false: print('no');
}

default_ 分支可覆盖所有可能值,使 switch 对任意类型完备。

枚举和密封类型特别适合 switch——即使无 default 分支,其所有可能值也是已知且可枚举的。通过 sealed 修饰类,可在子类切换时启用完备性检查:

dart
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 子类,该表达式将不完整,完备性检查会提示缺失的子类型。这种机制支持类似函数式代数数据类型的编程风格。


守卫子句

case 子句后添加可选守卫条件时,使用关键字 when。守卫可跟在 ifswitch(语句或表达式)之后:

dart
// switch 语句中的守卫
switch (something) {
  case somePattern when some || boolean || expression: 
    //             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 守卫子句
    body;
}

// switch 表达式中的守卫
var value = switch (something) {
  somePattern when some || boolean || expression => body,
  //               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 守卫子句
};

// if-case 语句中的守卫
if (something case somePattern when some || boolean || expression) {
  //                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 守卫子句
  body;
}

守卫会在模式匹配后评估任意布尔表达式,从而对分支执行添加额外约束。若守卫为 false,控制流会跳至下一 case 而非直接退出 switch