分支控制流

一、if /if-else 基础分支

  1. if 括号内必须是布尔表达式,不能隐式转布尔
  2. 支持多段 else if,最后可选 else
  3. 单行可省略大括号,推荐统一加花括号提升可读性
void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("带雨衣");
  } else if (isSnowing) {
    print("穿厚外套");
  } else {
    print("开敞篷车");
  }
}Code language: Dart (dart)

执行结果

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
穿厚外套Code language: CSS (css)

也可以单独使用if

void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("带雨衣");
  }
}Code language: Dart (dart)

或者就if else

void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("带雨衣");
  } else {
    print("开敞篷车");
  }
}Code language: Dart (dart)

二、if-case 模式匹配分支(Dart3.0+)

  1. 匹配模式,匹配成功则解构绑定变量到当前作用域
  2. 匹配失败走 else;支持 when 守卫追加布尔判断
  3. 只针对单个值单模式匹配,多模式匹配用 switch
void main() {
  final pair = [100, 220];
  // 匹配长度2、两个int的列表
  if (pair case [int x, int y]) {
    print("坐标:$x,$y");
  } else {
    throw FormatException("无效坐标");
  }
}Code language: Dart (dart)

执行结果

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
坐标:10,20Code language: CSS (css)

2:if-case 结合 when 守卫

void main() {
  final data = [8, 9];
  if (data case [int a, int b] when a > 5 && b > 5) {
    print("两个数字都大于5");
  } else {
    print("数字不满足条件");
  }
}Code language: Dart (dart)

执行结果

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
两个数字都大于5Code language: CSS (css)

三、switch 语句

传统 switch,语句形式,没有返回值

  1. case 支持任意模式:字符串、常量、逻辑或、关系模式
  2. 非空 case 自动 break,不用手动写 break;空 case 自动穿透
  3. 手动穿透两种方式:continue 标签 / 空 case 连续写
  4. default 最终都不匹配的时候就执行;支持 when 守卫
1:基础字符串匹配
void main() {
  String command = "OPEN";
  switch (command) {
    case "CLOSED":
      print("执行关闭逻辑");
    case "PENDING":
      print("执行等待逻辑");
    case "OPEN":
      print("执行打开逻辑");
    default:
      print("未知指令");
  }
}
Code language: Dart (dart)

执行结果

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
执行打开逻辑Code language: CSS (css)

2:空 case 穿透 + continue 标签跳转

String command = "OPEN";
switch (command) {
  case "OPEN":
    print("打开操作"); // ① 匹配到 OPEN,执行打印
    continue newCase; // ② 直接跳转到 newCase: 位置,不再回头

  case "DENIED": 
  case "CLOSED":
    print("关闭操作");

  newCase: // ③ 跳转目标点
  case "PENDING":
    print("待处理统一逻辑"); // ④ 直接执行这里,不会判断 command == "PENDING"
}Code language: Dart (dart)

执行结果

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
打开操作
待处理统一逻辑Code language: CSS (css)

这个例子中 continue newCase; 是不是就跳转到了newCase: 这里 但是下一个 case “PENDING”: 不是不匹配吗 为什么还会执行print(“待处理统一逻辑”);?

应该很多读者有这个疑问

continue label; 不会重新匹配值,而是直接跳转到标签所在的 case 分支入口,不再做条件判断,直接执行分支内代码

3:switch + when

void main() {
  int score = 88;
  switch (score) {
    case int s when s >= 90:
      print("优秀");
    case int s when s >= 60:
      print("及格");
    default:
      print("不及格");
  }
}
Code language: Dart (dart)

输出及格

先匹配类型 发现必须都是int类型,如果是int类型 就赋值给s ,如果符合后,再进行后面的when守卫,它进行二次校验,如果s的值符合 when后面的条件,才执行case后面的语句。再这里,虽然又两个int s 但是作用域是不一样的。

每个 case int s各自独立的模式绑定,作用域只在当前这个 case 分支内部,互不干扰

你完全可以给两个不同的变量名。效果一模一样。

switch (score) {
  case int a when a >= 90:
    print("优秀");
  case int b when b >= 60:
    print("及格");
  default:
    print("不及格");
}Code language: Dart (dart)

四、switch 表达式

需要是Dart3.0+后才支持的语法,有返回值,常用赋值

和 switch 语句区别

  1. case 关键字,用 => 分隔模式与表达式
  2. 每个分支必须返回表达式,逗号分隔分支
  3. 无隐式穿透,每个分支独立;最终都不匹配的时候用下划线 _ 不能用 default
  4. 可直接赋值、print、return,所有表达式通用

1:基础字符运算符匹配(逻辑或模式)

void main() {
  const slash = 47, star = 42, comma = 44;
  int charCode = 42;

  final token = switch (charCode) {
    slash || star => "运算符",
    comma => "标点",
    _ => "无效字符"
  };
  print(token);
}
Code language: Dart (dart)

运行结果

运算符

本例子中,规定了三个符号的ASCII码的常量,然后有一个是变量charCode ,然后下面判断这个变量,是否属于运算符或者标点符号,还是其他的符号。

2:switch 表达式 + when 守卫

void main() {
  int age = 22;
  String level = switch (age) {
    int a when a < 18 => "未成年",
    int a when a < 30 => "青年",
    _ => "成年"
  };
  print(level);
}Code language: Dart (dart)

运行结果

青年

3:函数 return 中直接使用 switch 表达式

void main() {
  print(getDesc(3));
}

String getDesc(int num) => switch (num) {
  1 => "一",
  2 => "二",
  _ => "其他数字"
};
Code language: Dart (dart)

执行结果

其他数字

注意:这里是switch是表达式,然后getDesc是一个箭头函数,箭头函数是dart区别其他类C语言的一个语法。

五、穷尽性校验 Exhaustiveness Checking

编译报错:当传入值存在无法匹配的分支,强制补全 case;密封类 sealed、enum 天然支持穷尽校验,不需要 _ / default。

1:可空布尔 非穷尽报错(读者可以注释运行看报错)

void main() {
  bool? nullableBool = null;
  // 下面代码取消注释会编译报错:缺少null匹配分支,同时也没有default _的兜底
  /*
  switch (nullableBool) {
    case true:
      print("是");
    case false:
      print("否");
  }
  */
  // 修复:增加null分支或_兜底
  switch (nullableBool) {
    case true:
      print("是");
    case false:
      print("否");
    case null:
      print("空值");
  }
}Code language: PHP (php)

执行结果

空值

2:sealed 密封类

代数数据类型,强制穷尽匹配

import 'dart:math' as math;

// 密封类:只能在当前文件实现子类
sealed class Shape {}

// 子类 方形边长
class Square implements Shape {
  final double length;
  Square(this.length);
}

//子类 圆形半径
class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

//一个箭头函数根据传入的子类对象进行switch匹配调用那个函数
double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(radius: var r) => math.pi * r * r
  // 新增Shape子类会直接编译报错,提示缺少对应case
};

void main() {
  final Shape circle = Circle(5);
  print(calculateArea(circle));
  final Shape square = Square(4);
  print(calculateArea(square));
}
Code language: Dart (dart)

执行结果

78.53981633974483
16.0Code language: CSS (css)

3:Enum 枚举穷尽匹配

不需要下划线_兜底

void main() {
  final Animal animal = Animal.cat;
  String name = switch (animal) {
    Animal.dog => "小狗",
    Animal.cat => "小猫"
  };
  print(name);
}

enum Animal { dog, cat }
Code language: Dart (dart)

输出小猫

由于enum枚举已经又一定的范围,不会出现其他值了,所以不需要兜底。

六、when 守卫

if-case /switch 语句 /switch 表达式全覆盖

when 作用:模式匹配成功后,再追加布尔判断;守卫 false 则进入下一分支,不会退出 switch。

1. if-case + when

void main() {
  List<int> arr = [10, 20];
  if (arr case [int x, int y] when x + y > 20) {
    print("两数之和大于20");
  }
}Code language: Dart (dart)
两数之和大于20

先匹配类型 是不是两个int的列表,符合后再使用when来判断它们的和是不是大于20

2. switch 语句 + when

void main() {
  int num = 15;
  switch(num) {
    case int n when n % 2 == 0:
      print("偶数");
    case int n when n % 2 != 0:
      print("奇数");
  }
}
Code language: PHP (php)

输出 奇数

先判断int类型,然后判断when。

3. switch 表达式 + when

void main() {
  int num = 15;
  String res = switch(num) {
    int n when n % 2 == 0 => "偶数",
    _ => "奇数"
  };
  print(res);
}
Code language: PHP (php)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注