• 【Dart】004-流程控制


    Dart】004-流程控制

    说明:对于一个 java 程序员来讲,这太简单了!学习过程非常无聊,所以对教程做了很多摘录!

    一、条件流程

    摘录:根据条件的满足情况,来执行不同的逻辑代码块,这就是 条件流程 的作用。Dart 编程中,主要有两种语法形式:if 条件语句和 switch 条件语句,两者适用于不同的场景。

    在现实生活中,if...else... 的语境是 如果...就...否则...就... ,而 switch当...时,就...

    1、if 语句

    概述

    ifbool 型变量形影不离,它会根据条件的真假,来执行不同的代码块。所以一个 if...else 语句可以表示两段分支的抉择,另外如果 else 代码块中没有处理内容,可以省略

    闲聊*:这些东西,基本所有的编程语言都是极为相似的!

    两个分支判断

    import 'dart:math';
    
    main() {
      bool condition = Random().nextBool();
      if (condition) {
        // condition = true 时执行逻辑
      } else {
        // condition = false 时执行逻辑
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    多个分支判断使用 else if

    import 'dart:math';
    
    main() {
      // 获取随机数
      int random = Random().nextInt(100);
      // 多分支判断
      if (random < 50) {
        print('小于50');
      } else if (random < 80) {
        print('小于80');
      } else {
        print('大于等于80');
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2、switch 语句

    概述

    if 通过对 bool 型变量进行检验,来选择执行的分支。 switch 是针对一般对象进行的校验,按分支执行,可以说 switch 是更高级的分支结构。它可以很轻松地实现多分支的结构,而不必像 if..else 那样冗长的判断。

    代码示例

    import 'dart:math';
    
    main() {
      // 获取随机数
      int random = Random().nextInt(3);
      // switch 语句
      switch (random) {
        case 0:
          print('0');
          break;
        case 1:
          print('1');
          break;
        case 2:
          print('2');
          break;
        default:
          print('default');
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    switch 校验对象的两个限制

    1. case 后面匹配值,必须是 常量;
    2. 自定义的类型不可以重写并实现 == 方法(顺带说一句,像 Stringint 这样的类中,确实覆写了 == 操作符,但在 dart 层并未实现,这是允许的。)。

    二、循环流程

    一般编程中的主要循环是 for 循环和 while 循环。

    1、标准 for 循环

    基本的编程语言都有 for 循环,这里不做过多阐述。

    摘录教程:标准的 for 循环结构如下,for 关键字后的括号中有三个部分,且通过 ; 隔开。其中 startExp 是进入循环体前执行的表达式,只会执行一次; conditionbool 型的变量,相当于循环的 阀门 ,只有为 true 时,才允许执行循环体。eachLoopExp 是在每次循环体结束之后触发的表达式,一般用于修改 condition 的条件。

    语法格式

    for ( startExp ; condition ; eachLoopExp ) {
      loopBody
    }
    
    • 1
    • 2
    • 3

    代码演示

    main() {
      // 一个字符串列表
      List<String> list = ['apples', 'bananas', 'oranges'];
      // 使用 for 循环遍历列表
      for (int i = 0; i < list.length; i++) {
        print(list[i]);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行结果

    apples
    bananas
    oranges
    
    • 1
    • 2
    • 3

    2、for…in 循环

    摘录:for...in 只是对列表遍历的一个语法糖,它可以屏蔽循环三大件,直接遍历访问元素。这样有益有弊,好处是使用方便,坏处是无法直接感知遍历到的索引位置。

    代码演示

    main() {
      // 一个字符串列表
      List<String> list = ['apples', 'bananas', 'oranges'];
      // 使用 for...in 循环遍历列表
      for (String item in list) {
        print(item);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行结果

    apples
    bananas
    oranges
    
    • 1
    • 2
    • 3

    3、while 循环

    概述

    while 循环的结构比较简单,但它要比 for 循环更难理解一点。while 关键字后的括号中填入校验条件,条件满足会进入循环体。从这可以看出,必须在 conditionloopBody 中动态修改条件,否则就会死循环。

    语法格式

    while (condition) {
      loopBody
    }
    
    • 1
    • 2
    • 3

    while 循环与 for 循环的等价改写

    for 循环和 while 循环本质上没有什么区别,两者可以进行相互转化。其实对于循环而言,最重要的是对校验条件的维,如下是通过 while 循环对上面 for 循环的等价改写。

    List<String> cnNumUnits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
    int i = 0;
    bool condition = i < cnNumUnits.length;
    while (condition){
      print(cnNumUnits[i]);
      i++;
      condition = i < cnNumUnits.length;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    代码演示

    main() {
      // 一个字符串列表
      List<String> list = ['apples', 'bananas', 'oranges'];
      // 使用 while 循环遍历列表
      int index = 0;
      while (index < list.length) {
        print(list[index]);
        index++;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果

    apples
    bananas
    oranges
    
    • 1
    • 2
    • 3

    4、do…while 循环

    概述摘录

    do...while 作为循环的一种,和前两者也没有什么本质性的区别,都是依靠校验条件来不断执行循环体。它有一个最大的特点,就是:loopBody 至少执行一次,而 forwhile 可能会由于条件不满足而一次都不执行。

    语法格式

    do {
        loopBody
    } while(condition)
    
    • 1
    • 2
    • 3

    代码演示

    main() {
      // 一个字符串列表
      List<String> list = ['apples', 'bananas', 'oranges'];
      // 使用 do while 循环遍历列表
      int i = 0;
      do {
        print(list[i]);
        i++;
      } while (i < list.length);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果

    apples
    bananas
    oranges
    
    • 1
    • 2
    • 3

    三、中断流程

    摘录:对于循环来说有个非常重要的事:如何中断循环。正常来说,循环的终止是靠修改校验条件实现的。除此之外,我们还有其他的手段在 循环体内 中断或终止流程。常用的关键字有:

    continue
    break
    return
    
    • 1
    • 2
    • 3

    1、continue 关键字

    概述摘录

    continue 表示该 循环体到此执行完毕,进入下一次循环。比如下面案例中,当 i 是偶数时,tag1 触发 continue ,比如当 i = 2 时,该次循环到此结束,也就是下一步不会到达 tag2 。进入下一次循环,是指触发 eachLoopExp 表达式,这里是 i++ ,由于循环条件仍然满足,所以会继续进入循环,此时 `i = 3

    代码示例

    int sum = 0;
    for (int i = 0; i < 10; i++) {
      if(i.isEven){// 如果是偶数
        continue; //tag1
      }
      sum += i; //tag2
      print("第 $i 次循环,计入 sum");
    }
    print("sum: $sum");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2、break 关键字

    概述摘录

    break 相对而言就比较 "强硬" 一些,只要某次循环中走到 break , 就会完全中断循环,不会进入下次循环。把上面代码的 tag1 处改为 break ,也就是说只要 i 是偶数,整个循环就会被完全终止。

    代码示例

    int sum = 0;
    for (int i = 0; i < 10; i++) {
      if(i.isEven){// 如果是偶数
        break; //tag1
      }
      sum += i; //tag2
      print("第 $i 次循环,计入 sum");
    }
    print(sum); // tag3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3、return 关键字

    概述摘录

    严格来说,return 关键字并非用于循环的流程控制,而是表示当前方法已经结束。由于方法结束,其中的循环自然也就不会再进行了。比如下面 tag1 处如果是 return ,那么该方法直接退出。连 tag3 都不会执行。

    代码示例

    int sum = 0;
    for (int i = 0; i < 10; i++) {
      if(i.isEven){// 如果是偶数
        return; //tag1
      }
      sum += i; //tag2
      print("第 $i 次循环,计入 sum");
    }
    print("sum: $sum"); // tag3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    四、异常流程

    摘录:在程序运行的过程中,可能会出现一些可以预见的错误:比如,网络异常、文件读取异常、日期格式化异常、数值越界异常等。一旦发生异常,不作处理的话,整个程序就会因错误而停止,无法执行之后的任务。另外异常的信息记录也能让开发者更容易定位问题,所以对异常的捕获和处理是非常重要的。

    1、异常的发生

    如下测试案例中 task1 方法将入参字符串转换为数字,如果传入非数字,就会产生转换异常。从而中断程序,导致 task2 无法触发。

    void main(){
      task1('a');
      task2();
    }
    
    int task1(String num){
      return int.parse(num);
    }
    
    void task2(){
      print("Task2");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2、异常的捕捉

    通过 try...catch... 可以对异常进行捕捉。在 catch 关键字后的括号中可以回调两个参数,如下

    • e 表示异常对象,此处为 FormatException
    • s_StackTrace 对象,用于记录异常的栈信息
    void main(){
      try{
        task1('a');
      }catch(e,s){
        print("${e.runtimeType}: ${e.toString()}"); 
        print("${s.runtimeType}: ${s.toString()}"); 
      }
      task2(); // Task2
    }
    
    int task1(String num){
      return int.parse(num);
    }
    
    void task2(){
      print("Task2");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3、自定义异常与抛出

    异常的顶层抽象类是 Exception ,其中有个 factory 构造。也就是说 Exception 可以进行构造,本质上创建的运行时类型是 _Exception ,可传入一个对象用于表示异常信息。

    exception

    如下做个简单的测试,在 getMean 方法中,传入单词名称,根据映射表来获取单词示意。当没有示意时,抛出异常,通过 throw 关键字,后面加 Exception 对象即可。

    void main() {
      try {
        getMean("about");
      } catch (e,s) {
        print("${e.runtimeType}: ${e.toString()}");
        print("${s.runtimeType}: ${s.toString()}");
      }
    }
    
    String getMean(String arg) {
      Map<String, String> dict = {"card": "卡片", "but": "但是"};
      String? result = dict[arg];
      if (result == null) {
        throw Exception("empty $arg mean in dict");
      }
      return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    有些场景可能存在多种不同的异常,我们期望可以区别对待,我们可以对 Exception 类进行拓展。如下自定义一个 NoElementInDictException 表示映射中没有相关元素的异常:

    class NoElementInDictException implements Exception{
      final String arg;
    
      NoElementInDictException(this.arg);
    
      
      String toString() => "empty $arg mean in dict";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    另外,一个方法可能抛出多种异常,如果希望明确抓取的类型种类,可以通过 on/catch 关键字创建分支。注意,允许有若干个 on 分支进行不同类型异常处理,对于未匹配到的异常,会走默认的 catch 分支。

    void main() {
      try {
        getMean("about");
      } on NoElementInDictException catch(e,s){
        // 特定种类的异常处理
      } catch (e,s) {
        // 其余异常处理
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4、final 关键字

    finally 关键字用于 catch 代码块之后,无论异常与否,其后代码块的逻辑总会被执行。如果不用 finally 关键字,那就需要在每个异常分支以及外界都写一遍 finally 代码块,这无疑是很麻烦的。这也是 finally 关键字的价值所在。

    void foo2(){
      try {
        getMean("about");
      } catch (e,s) {
        print("${e.runtimeType}: ${e.toString()}");
        print("${s.runtimeType}: ${s.toString()}");
      } finally{
        print("finally bloc call");
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    Django后台管理(二)
    redis的安装、基础命令及常用数据结构
    Java8中的Stream流
    Solitidy - fallback 回退函数 - 2种触发执行方式
    集合框架的总结1
    如何精准识别主数据?
    Spring及Spring boot 第二章 AOP 源码 AopProxy系列
    springboot外委员工后台管理系统毕业设计源码101157
    windows pwn(一)
    结构型-代理模式
  • 原文地址:https://blog.csdn.net/qq_29689343/article/details/127830519