Dart基礎系統學習

楊充發表於2019-07-01

目錄介紹

  • 01.變數宣告
    • 1.1 var宣告變數
    • 1.2 變數和常量
    • 1.3 dynamic和Object
  • 02.資料型別
    • 2.1 基本資料型別
    • 2.2 String字串
    • 2.3 List陣列
    • 2.4 Map集合
  • 03.Dart函式和運算子
    • 3.1 Dart函式介紹
    • 3.2 命名引數
    • 3.3 引數預設值
    • 3.4 void無返回值
    • 3.5 匿名函式
    • 3.6 運算子介紹
  • 04.Dart流程控制
    • 4.1 流程控制語句
    • 4.2 if和else
    • 4.3 for迴圈
    • 4.4 while迴圈
    • 4.5 break和continue
    • 4.6 switch和case
    • 4.7 assert斷言
  • 05.Dart物件導向
    • 5.1 類簡單介紹
    • 5.2 建構函式
    • 5.3 繼承類
    • 5.4 過載和重寫
    • 5.5 抽象類
    • 5.6 訪問許可權
    • 5.7 靜態方法
    • 5.8 泛型
  • 06.Dart非同步解讀
    • 6.1 Future簡單介紹
      • 6.1.1 普通非同步案例
      • 6.1.2 耗時非同步案例
    • 6.2 async/await介紹
    • 6.3 看一個案例
  • 07.Dart異常捕獲
    • 7.1 異常處理形式
    • 7.2 丟擲異常
    • 7.3 捕獲異常
    • 7.4 Finally講解
  • 08.Dart列舉
    • 8.1 列舉使用
    • 8.2 後設資料
    • 8.3 自定義註解
  • 09.Dart字串
    • 9.1 String簡單介紹
    • 9.2 單雙引號互相巢狀
    • 9.3 字串拼接方式

01.變數宣告

1.1 var宣告變數

  • 類似於kotlin中的var,它可以接收任何型別的變數,但最大的不同是Dart中var變數一旦賦值,型別便會確定,則不能再改變其型別,如:
    var t;
    t="yc";
    // 下面程式碼在dart中會報錯,因為變數t的型別已經確定為String,
    // 型別一旦確定後則不能再更改其型別。
    t=1000;
    複製程式碼
    • 最大的不同是Dart中var變數一旦賦值,型別便會確定,則不能再改變其型別。因為Dart本身是一個強型別語言,任何變數都是有確定型別的,在Dart中,當用var宣告一個變數後,Dart在編譯時會根據第一次賦值資料的型別來推斷其型別,編譯結束後其型別就已經被確定。
  • 思考一下,dart在編譯時是如何確定資料的型別呢?

1.2 變數和常量

1.2.1 變數
  • 變數如下所示
    var curPage = 0;
    var title = "瀟湘劍雨:小楊逗比";
    複製程式碼
  • Dart 不需要給變數設定 setter getter 方法, 這和 kotlin 等類似。Dart 中所有的基礎型別、類等都繼承 Object ,預設值是 NULL, 自帶 getter 和 setter ,而如果是 final 或者 const 的話,那麼它只有一個 getter 方法。
1.2.2 常量
  • const 的值在編譯期確定,final 的值要到編譯時才確定。
    • Dart 中 final 表示常量
      //final 表示常量
      final title = "瀟湘劍雨:小楊逗比";
      複製程式碼
    • static const 組合代表了靜態常量
      //static const 組合代表了靜態常量
      static const String complete = "COMPLETE";
      複製程式碼
  • final和const區別
    • 兩者區別在於:const 變數是一個編譯時常量,final變數在第一次使用時被初始化。被final或者const修飾的變數,並且變數型別可以省略。
  • 注意點
    • const變數同時也是final變數,例項變數可以為final但不能是const。
    • 編譯錯報錯,原因final變數只能賦值一次!
    //定義初始化一個變數
    final double number = 13.14;
    number = 520;
    //呼叫列印數字方法
    printNumber(number);
    複製程式碼
1.2.3 注意+
  • 在Java中可以直接通過 + 號將字串和int型別拼接,但是在Dart中是不行的。
    //在Java中,下面操作可行
    ToastUtils.showRoundRectToast("二維碼掃描"+1000);
    
    //在dart中,下面錯誤操作,編譯不通過,直接會有紅色提示
    int yc = 0;
    print("瀟湘劍雨" + yc);
    
    //在dart中,下面正確操作
    int yc = 0;
    print("瀟湘劍雨" + yc.toString());
    複製程式碼

1.3 dynamic和Object

  • Object 是dart所有物件的根基類,也就是說所有型別都是Object的子類(包括Function和Null),所以任何型別的資料都可以賦值給Object宣告的物件.
    • dynamicvar一樣都是關鍵詞,宣告的變數可以賦值任意物件.而dynamicObject相同之處在於,他們宣告的變數可以在後期改變賦值型別.
    dynamic t;
    Object x;
    t = "hi world";
    x = 'Hello Object';
    //下面程式碼沒有問題
    t = 1000;
    x = 1000;
    複製程式碼
    • dynamicObject不同的是,dynamic宣告的物件編譯器會提供所有可能的組合,而Object宣告的物件只能使用Object的屬性與方法, 否則編譯器會報錯. 如:
     dynamic a;
     Object b;
     main() {
         a = "";
         b = "";
         printLengths();
     }   
    
     printLengths() {
         // no warning
         print(a.length);
         // warning:
         // The getter 'length' is not defined for the class 'Object'
         print(b.length);
     }
    複製程式碼
    • 變數a不會報錯, 變數b編譯器會報錯
      • dynamic的這個特性與Objective-C中的id作用很像.
      • dynamic的這個特點使得我們在使用它是需要格外注意,這很容易引入一個執行時錯誤.

02.資料型別

2.1 基本資料型別

  • var 可以定義變數,同時 Dart 屬於動態型別語言,支援閉包。
    • Dart 中 number 型別分為 int 和 double ,其中 java 中的 long 對應的也是 Dart 中的 int 型別。Dart 中沒有 float 型別。
    //int型別   這裡沒有long型別
    var positionIndex = 0;
    
    //double型別   這裡沒有float型別
    var time = 1993.03;
    複製程式碼
    • 這裡提個小建議,宣告變數的時候,可以選擇加上具體型別。新增型別可以更加清晰表達你的意圖。
    //定義初始化一個變數
    double number = 13.14;
    複製程式碼
  • Dart 下只有 bool 型可以用於 if 等判斷,不同於 JS 這種使用方式是不合法的 var g = "null"; if(g){} 。
    • 以bool代表布林值,只有兩個物件是布林型別的,那就是true和false所建立的物件,這兩個物件都是編譯時常量。
    //類似Java中的布林型別
    bool mIsLogin = false;
    
    if (!mIsLogin) {
      //沒有登陸
      print('沒有登陸');
    } else {
      //已經登陸
      Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
        return new CollectPage();
      }));
    }
    複製程式碼
    • 注意,下面這種情況會報錯
    String name ="yc";
    //報錯 因為name不是bool型別
    if(name){
      print(name);
    }
    複製程式碼
    • 可以使用的是先式的檢查值。assert是語言內建的斷言的函式,僅在檢查模式有效,在開發過程中,除非條件為真,否則會引發異常。(斷言失敗則程式立刻終止)
    // 檢查是否為空字串
    var fullName = 'doubi';
    assert(fullName.isEmpty);
    
    // 檢查是否小於等於0
    var hitPoints = 0;
    assert(hitPoints <= 0);
    
    // 檢查是否為 null.
    var unicorn;
    assert(unicorn == null);
    
    // 檢查是否為 NaN.
    var iMeantToDoThis = 0 / 0;
    assert(iMeantToDoThis.isNaN);
    複製程式碼

2.2 String字串

  • Dart 中,switch 支援 String 型別。後面會單獨拿出來講解一下。
    //字串
    var title = "瀟湘劍雨:小楊逗比";
    複製程式碼

2.3 List陣列

  • 宣告一個list非常的簡單,可以簡單使用方括號[]定義list。下面是list的常用操作。
    main(List<String> args) {
      //或者
      List arr1 = [1,2,3,4];
      var arr2 = [1,2,3,4];
     
      print(list); //Output: [1, 2, 3, 4]
      //Length 長度
      print(list.length);
     
      //Selecting single value 獲取單個值
      print(list[1]);    //Outout: 2
     
      //Adding a value 新增值到list
      list.add(10);
     
      //Removing a single isntance of value 刪除單個值
      list.remove(3);
     
      //Remove at a particular position 刪除指定位置的值
      list.removeAt(0);
    }
    複製程式碼
    • 注意:第一個元素索引是0,最後一個元素是length-1
  • 如果你想定義一個編譯時常量list,例如,list的內容是不可改變的,可以使用關鍵字const
    var list = const [1,2,3,4];   
    複製程式碼

2.4 Map集合

  • 定義map也很簡單。可以使用花括號{}定義map。
      void test() {
        var map = {
          'key1': 'value1',
          'key2': 'value2',
          'key3': 'value3'
        };
        //Fetching the values 獲取值
        print(map['key1']);    //Output: value1
        print(map['test']);    //Output: null
    
        //Add a new value 新增值
        map['key4'] = 'value4';
    
        //Length   獲取長度
        print(map.length);
    
        //Check if a key is present 檢查是否存在
        var containsKey = map.containsKey('value1');
        print(containsKey);
    
        var entries = map.entries;
        var values = map.values;
      }
    複製程式碼
    • 列印日誌
    2019-06-20 17:22:39.200 4281-4329/com.hwmc.auth I/flutter: value1
    2019-06-20 17:22:39.200 4281-4329/com.hwmc.auth I/flutter: null
    2019-06-20 17:22:39.200 4281-4329/com.hwmc.auth I/flutter: 4
    2019-06-20 17:22:39.200 4281-4329/com.hwmc.auth I/flutter: false
    複製程式碼
  • 也可以使用map建構函式定義map。
    • 可以發現map可以儲存多種型別的資料
    var squares = new Map();
    squares["a"] = 1;
    squares["b"] = 2;
    squares["c"] = 3.0;
    squares["d"] = [1,2];
    squares["e"] = "yc逗比";
    
    print(squares['a']);    
    print(squares['e']);
    複製程式碼
    • 列印日誌
    2019-06-20 17:27:32.841 4281-4329/com.hwmc.auth I/flutter: 1
    2019-06-20 17:27:32.841 4281-4329/com.hwmc.auth I/flutter: yc逗比
    複製程式碼

03.Dart函式和運算子

3.1 Dart函式介紹

  • dart中的函式和JavaScript中有點類似。你需要定義就是函式的名字、返回值(有返回值或者void)、引數。
      void test(){
        var name = fullName('楊充', '逗比');
        print(name);
      }
    
      String fullName(String firstName, String lastName) {
        return "$firstName $lastName";
      }
    複製程式碼

3.2 命名引數

  • dart有個叫命名引數的東西。當你呼叫函式的時候,你必須指定引數的名字。要使用命名引數,可以將函式的引數包括在花括號{}內。
    • 如果你在呼叫命名引數的函式時,沒有指定引數的名字,則會提示紅色報錯,無法通過編譯。
      void test(){
        var name = fullName('楊充', '逗比');
        print(name);
      }
    
      String fullName(String firstName, String lastName) {
        return "$firstName $lastName";
      }
    複製程式碼

3.3 引數預設值

  • 你可以給函式的命名引數一個預設值。下面的例子給lastName一個預設值。
      void test(){
        var name = fullName('楊充', '逗比');
        print(name);
      }
    
      fullName(String firstName, String lastName) {
        return "$firstName $lastName";
      }
    複製程式碼

3.4 void無返回值

  • 大多數都是void無返回值的函式,這個跟java中類似。沒什麼好講的……

3.5 匿名函式

  • 在dart中函式比較靈活,例如,你可以將函式當引數傳遞給另一個函式。
      void test(){
        out(printOutLoud);
      }
    
      out(void inner(String message)) {
        inner('Message from inner function');
      }
    
      printOutLoud(String message) {
        print(message.toUpperCase());
      }
    複製程式碼
    • 這裡定義一個函式名字為out,需要一個函式引數。然後我定義一個名為printOutLoud的函式,他所做的就是將字串以大寫的形式列印。
    • dart 也有匿名函式,所以上面的例子中不用預定一個函式,而是傳遞一個匿名函式。
  • 另一個匿名函式的例子。
    
    複製程式碼

3.6 運算子介紹

  • 這部分和java差不多,可以直接看我java部分的部落格:運算子

04.Dart流程控制

4.1 Dart流程控制

  • 大概有這麼多
    • if和else
    • for迴圈
    • while迴圈
    • break和continue
    • switch和case
    • assert斷言

4.2 if和else

  • if-else 和其他語言一樣比較簡單。
    var number = 57;
    if (number > 100) {
      print('Large Number');
    } else if (number < 100) {
      print('Small Number');
    } else {
      print('Number is 100');
    }
    複製程式碼
  • 可以用三元運算子代替if-else
    int age = 60;
    String status = age < 50 ? "年輕人" : "老年人";
    複製程式碼

4.3 for迴圈

  • for迴圈和java幾乎是一樣的,程式碼如下
      void test() {
        for (int i = 0; i < 10; i++) {
          print('$i');
        }
      }
    複製程式碼

4.4 while迴圈

  • while迴圈如下所示
      void test() {
        int i = 0;
        while(i < 10) {
          print('$i');
          i++;
        }
      }
    複製程式碼
  • The classic for do while loop. 典型的do while迴圈。
      void test() {
        int i = 0;
        do {
          print('$i');
          i++;
        } while (i < 10);
      }
    複製程式碼

4.6 break和continue

4.7 switch和case

  • 程式碼如下所示
      void test() {
        int age = 50;
        switch(age) {
          case 10:
            print('Too Young.');
            break;
          case 20:
          case 30:
            print('Still Young!');
            break;
          case 40:
            print('Getting old.');
            break;
          case 50:
            print('You are old!');
            break;
        }
      }
    複製程式碼

06.Dart非同步解讀

6.1 Future簡單介紹

  • async 庫中有一個叫Future的東西。Future是基於觀察者模式的。如果你熟悉Rx或者JavaScript的Promises,你就很容易明白了。
    • 首先先看一下下面的案例,看看它們之間有什麼區別?
      void testA() async{
        new Future<String>(() {
          return "This is a doubi";
        });
      }
    
      Future testB() async{
        return new Future<String>(() {
          return "This is a doubi";
        });
      }
    
      Future<String> testC() {
        return new Future<String>(() {
          return "This is a doubi";
        });
      }
    複製程式碼
6.1.1 普通非同步案例
  • Future是支援泛型的,例如Future,通過T指定將來返回值的型別。
    • 定義了一個叫getTest的函式,返回值為Future.你可以通過new關鍵字建立一個Future。Future的建構函式,需要一個函式作為引數,這個函式返回T型別的資料。在匿名函式中的返回值就是Future的返回值。
    • 當呼叫了getTest方法,他返回Future.我們通過呼叫then方法訂閱Future,在then中註冊回撥函式,當Future返回值時呼叫註冊函式。同時註冊了catchError方法處理在Future執行之間發生的異常。這個例子中不會發生異常。
      void test() {
        getTest().then((value) {
          print("測試----------"+value);
        }).catchError((error) {
          print('測試----------Error');
        });
      }
    
      Future<String> getTest() {
        return new Future<String>(() {
          return "This is a doubi";
        });
      }
      
      //列印結果
      2019-06-21 17:11:12.941 16501-16583/com.hwmc.auth I/flutter: 測試----------This is a doubi
    複製程式碼
    • 下面這個案例會發生異常
      void test() {
        getTest().then((value) {
          print("測試----------"+value);
        }).catchError((error) {
          print('測試----------Error');
        });
      }
    
      Future<String> getTest() {
        return new Future<String>(() {
          return "This is a doubi";
        });
      }
      
      //列印結果
      2019-06-21 17:18:46.896 16501-16583/com.hwmc.auth I/flutter: 測試----------Error
    複製程式碼
6.1.2 耗時非同步案例
  • 在生產環境中都是一些耗時的操作,例如,網路呼叫,我們可以使用Future.delayed()模仿。
    • 現在如果你執行,你將需要2秒,才能返回結果。
      void test() {
        getTest().then((value) {
          print("測試----------"+value);
        }).catchError((error) {
          print('測試----------Error');
        });
      }
    
      Future<String> getTest() {
        return new Future<String>.delayed(new Duration(milliseconds: 2000),() {
          return "This is a doubi";
        });
      }
    複製程式碼
    • 接下來再看一個案例。在呼叫函式之後,我們新增了print語句。在這種場景中,print語句會先執行,之後future的返回值才會列印。這是future的預期行為.但是如果我們希望在執行其他語句之前,先執行future。
      void test() {
        getTest().then((value) {
          print("測試----------"+value);
        }).catchError((error) {
          print('測試----------Error');
        });
        print('測試----------逗比是這個先執行嗎');
      }
    
      Future<String> getTest() {
        return new Future<String>.delayed(new Duration(milliseconds: 2000),() {
          return "This is a doubi";
        });
      }
      
      2019-06-21 17:26:16.619 16501-16583/com.hwmc.auth I/flutter: 測試----------逗比是這個先執行嗎
      2019-06-21 17:26:17.176 16501-16583/com.hwmc.auth I/flutter: 測試----------This is a doubi
    複製程式碼

05.Dart物件導向

5.1 類簡單介紹

  • 建立一個類和建立類的例項
    void test1(){
      Dog d = new Dog();
    }
    class Dog {
    
    }
    
    
    var cat = new Cat("逗比", 12);
    class Cat {
      String name;
      int age;
    
      Cat(String name, int age) {
        this.name = name;
        this.age = age;
      }
    }
    複製程式碼

5.2 建構函式

  • 普通建構函式
    var cat = new Cat("逗比", 12);
    
    class Cat {
      String name;
      int age;
    
      Cat(String name, int age) {
        this.name = name;
        this.age = age;
      }
    }
    複製程式碼
  • 命名建構函式
    • 給建構函式提供了名稱,這樣做使得不同的建構函式變的更加清晰。
    Map map = new Map();
    map['name']= "哈巴狗";
    map['age'] = 5;
    Dog d = new Dog.newBorn(map);
    
    
    class Dog {
      String name;
      int age;
    
      Dog(this.name, this.age);
    
      Dog.newBorn(Map json) {
        name = json['name'];
        age = json['age'];
      }
    }
    複製程式碼

5.3 繼承類

  • 可以使用extends關鍵字繼承其他的類。
    • Pug 類繼承Dog類,通過super關鍵字呼叫Dog類的建構函式。
    Pug p = new Pug('哈哈哈', 5);
    print(p.name);
    
    
    class Dog {
      String name;
      int age;
    
      Dog(this.name, this.age);
    
      Dog.newBorn() {
        name = 'Doggy';
        age = 0;
      }
    }
    
    class Pug extends Dog {
      Pug(String name, int age): super(name, age);
    }
    複製程式碼
  • 也可以通過this關鍵字,在冒號之後呼叫同一個類中的其他建構函式。
    • 定義了兩個命名建構函式,他們只需要dog的名字,然後呼叫Pug的預設建構函式。
    Pug p = new Pug.small('哈哈哈');
    print(p.name);
    
    class Dog {
      String name;
      int age;
    
      Dog(this.name, this.age);
    
      Dog.newBorn() {
        name = '逗比';
        age = 0;
      }
    }
    
    class Pug extends Dog {
      Pug(String name, int age): super(name, age);
    
      Pug.small(String name): this(name, 1);
    
      Pug.large(String name): this(name, 3);
    }
    複製程式碼

5.4 過載和重寫

  • 方法重寫
    • 程式碼如下,最後列印值是:你真是個逗比
    Pug p = new Pug();
    print(p.bark());
    
    class Dog {
      bark() {
        print('Bow Wow');
      }
    }
    
    class Pug extends Dog {
      @override
      bark() {
        print('你真是個逗比!');
      }
    }
    複製程式碼
  • 方法過載
    
    複製程式碼

5.5 抽象類

  • 可以通過abstract關鍵字宣告抽象類
    • 只需要在類宣告前新增abstract關鍵字,方法不需要。方法只需要簽名,不需要實現。
    abstract class AbstractDog {
      void eat();
      void _hiddenMethod();
    }
    
    class SmallDog extends AbstractDog{
      @override
      void _hiddenMethod() {
        
      }
    
      @override
      void eat() {
        
      }
    }
    複製程式碼

5.6 訪問許可權

  • 預設類中的所有屬性和方法是public的。在dart中,可以在屬性和方法名前新增“_”使私有化。現在讓我們使name屬性私有化。
    • 可以發現,呼叫私有化變數或者方法的時候會出現紅色警告
      void test() {
        Dog d = new Dog('哈巴狗', 5);
        //這個報錯
        print(d.name);
        print(d.age);
      }
    複製程式碼
    • Dog程式碼如下所示
    class Dog {
      String _name;
      int age;
    
      Dog(this._name, this.age);
    
      String get respectedName {
        return 'Mr.$_name';
      }
    
      set respectedName(String newName) {
        _name = newName;
      }
    
      Dog.newBorn() {
        _name = '哈巴狗';
        age = 0;
      }
    
      bark() {
        print('Bow Wow');
      }
    
      _hiddenMethod() {
        print('I can only be called internally!');
      }
    }
    複製程式碼

5.7 靜態方法

  • 如果想讓方法或者屬性靜態化,只需要在宣告前新增static關鍵字。
    void test() {
      Dog.bark();
    }
    
    
    class Dog {
      static bark() {
        print('Bow Wow');
      }
    }
    複製程式碼

5.8 泛型

  • dart全面支援泛型。假設你想在你定義的類中,想持有任意型別的資料。
    DataHolder<String> dataHolder = new DataHolder('Some data');
    print(dataHolder.getData());
    dataHolder.setData('New Data');
    print(dataHolder.getData());
    //下面這個會報錯,因為dataHolder物件在建立的時候就已經限制為String型別
    dataHolder.setData(123);
    print(dataHolder.getData());
    
    
    class DataHolder<T> {
      T data;
    
      DataHolder(this.data);
    
      getData() {
        return data;
      }
    
      setData(data) {
        this.data = data;
      }
    }
    複製程式碼

6.2 async/await介紹

  • 思考一下,看了上面的案例,對於future的預期行為,如果我們希望在執行其他語句之前,先執行future,該怎麼操作呢?
    • 這就需要用到需要用到async/await。在test函式的花括號開始新增async關鍵字。我們新增await關鍵字在呼叫getTest方法之前,他所做的就是在future返回值之後,繼續往下執行。我們將整個程式碼包裹在try-catch中,我們想捕獲所有的異常,和之前使用catchError回撥是一樣。使用awiat關鍵字,必須給函式新增async關鍵字,否則沒有效果。
    • 注意:要使用 await,其方法必須帶有 async 關鍵字。可以使用 try, catch, 和 finally 來處理使用 await 的異常!
      Future test() async {
        try {
          String value = await getTest();
          print("測試----------"+value);
        } catch(e) {
          print('測試----------Error');
        }
        print('測試----------逗比是這個先執行嗎');
      }
    
      Future<String> getTest() {
        return new Future<String>.delayed(new Duration(milliseconds: 2000),() {
          return "This is a doubi";
        });
      }
      
      2019-06-21 17:32:37.701 16501-16583/com.hwmc.auth I/flutter: 測試----------This is a doubi
      2019-06-21 17:32:37.702 16501-16583/com.hwmc.auth I/flutter: 測試----------逗比是這個先執行嗎
    複製程式碼

6.3 看一個案例

  • 一個 async 方法 是函式體被標記為 async 的方法。 雖然非同步方法的執行可能需要一定時間,但是 非同步方法立刻返回 - 在方法體還沒執行之前就返回了。
    void getHttp async {
        // TODO ---
    }
    複製程式碼
    • 在一個方法上新增 async 關鍵字,則這個方法返回值為 Future。
      • 例如,下面是一個返回字串的同步方法:
      String loadAppVersion() => "1.0.2"
      複製程式碼
    • 使用 async 關鍵字,則該方法返回一個 Future,並且 認為該函式是一個耗時的操作。
      Futre<String> loadAppVersion() async  => "1.0.2"
      複製程式碼
    • 注意,方法的函式體並不需要使用 Future API。 Dart 會自動在需要的時候建立 Future 物件。
  • 好的程式碼是這樣的
    void main() {
     //呼叫非同步方法
     doAsync();
    }
    
    // 在函式上宣告瞭 async 表明這是一個非同步方法
    Future<bool> doAsync() async {
      try {
        // 這裡是一個模擬請求一個網路耗時操作
        var result = await getHttp();
        //請求出來的結果
        return printResult(result);
      } catch (e) {
        print(e);
        return false;
      }
    }
    //將請求出來的結果列印出來
    Future<bool> printResult(summary) {
      print(summary);
    }
    
    //開始模擬網路請求 等待 5 秒返回一個字串
    getHttp() {
     return new Future.delayed(Duration(seconds: 5), () => "Request Succeeded");
    }
    複製程式碼
  • 不好的寫法
    void main() {
     doAsync();
    }
    
    Future<String> doAsync() async {
        return  getHttp().then((r){
          return printResult(r);
        }).catchError((e){
          print(e);
        });
    }
    
    Future<String> printResult(summary) {
      print(summary);
    }
    
    Future<String> getHttp() {
     return new Future.delayed(Duration(seconds: 5), () => "Request Succeeded");
    }
    複製程式碼

07.Dart異常捕獲

7.1 異常處理形式

  • dart 使用經典的try-catch處理異常,使用關鍵字throw丟擲一個異常。

7.2 丟擲異常

  • 看看如何丟擲異常
      void test1(){
        divide(10, 0);
      }
    
      divide(int a, int b) {
        if (b == 0) {
          throw new IntegerDivisionByZeroException();
        }
        return a / b;
      }
    複製程式碼
    • 當b變數的值為0的時候,丟擲一個內建的異常IntegerDivisionByZeroException。
  • 如何定義異常日誌呢?
    • 可以在異常中攜帶一個字串資訊。
      void test1(){
        divide(10, 0);
      }
    
      divide(int a, int b) {
        if (b == 0) {
          throw new Exception('逗比,不能為0的');
        }
        return a / b;
      }
    複製程式碼

7.3 捕獲異常

  • 某種型別的異常可以通過on關鍵字捕獲,如下:
      void test1(){
        try {
          divide(10, 0);
        } on IntegerDivisionByZeroException {
          print('逗比,異常被捕獲了');
        }
      }
    
      divide(int a, int b) {
        if (b == 0) {
          throw new IntegerDivisionByZeroException();
        }
        return a / b;
      }
    複製程式碼
  • 注意問題,捕獲的異常層級要大於丟擲的異常,否則捕獲會失敗
    • 還是會丟擲異常'逗比,不能為0的',因為Exception比IntegerDivisionByZeroException層級要高。
      void test1(){
        try {
          divide(10, 0);
        } on IntegerDivisionByZeroException {
          print('逗比,異常被捕獲了');
        }
      }
    
      divide(int a, int b) {
        if (b == 0) {
          throw new Exception('逗比,不能為0的');
        }
        return a / b;
      }
    複製程式碼
  • 如果你不知道丟擲異常的型別,或者不確定,可以使用catch塊處理任意型別的異常。
      void test1(){
        try {
          divide(10, 0);
        } on IntegerDivisionByZeroException {
          print('逗比,異常被捕獲了');
        } catch (e) {
          print(e);
        }
      }
    
      divide(int a, int b) {
        if (b == 0) {
          throw new Exception('yc other exception.');
        }
        return a / b;
      }
    複製程式碼

7.4 Finally講解

  • dart也提供了finally塊,即是否發生異常這個塊都會執行。
      void test1(){
        try {
          divide(10, 0);
        } on IntegerDivisionByZeroException {
          print('逗比,異常被捕獲了');
        } catch (e) {
          print(e);
        }finally {
          print('I will always be executed!');
        }
      }
    
      divide(int a, int b) {
        if (b == 0) {
          throw new Exception('yc other exception.');
        }
        return a / b;
      }
    複製程式碼

08.Dart列舉

8.1 列舉使用

  • dart 支援列舉,用法和java一樣。
    Dog d = new Dog('哈巴狗', 12, CurrentState.sleeping);
    print(d.state == CurrentState.sleeping); //Prints 'true'
    
    
    enum CurrentState {
      sleeping,
      barking,
      eating,
      walking
    }
    
    class Dog {
      String name;
      int age;
      CurrentState state;
    
      Dog(this.name, this.age, this.state);
    
      static bark() {
        print('Bow Wow');
      }
    }
    複製程式碼

8.2 後設資料

  • 使用後設資料給程式碼新增額外資訊,後設資料註解是以@字元開頭,後面是一個編譯時常量或者呼叫一個常量建構函式。
  • 有三個註解所有的Dart程式碼都可使用:@deprecated、@override,@proxy,下面直接上@deprecated的示例:

複製程式碼
  • 後設資料可以在library、typedef、type parameter、constructor、factory、function、field、parameter、或者variable宣告之前使用,也可以在import或者export指令之前使用,使用反射可以再執行時獲取後設資料資訊。

8.3 自定義註解

  • 定義自己的後設資料註解。下面的示例定義一個帶有兩個引數的@toDo註解:
    void test1() {
      doSomething();
    }
    
    
    @toDo('seth', 'make this do something')
    void doSomething() {
      print('do something');
    }
    
    class toDo {
      final String who;
      final String what;
      const toDo(this.who, this.what);
    }
    複製程式碼

09.Dart字串

9.1 String簡單介紹

  • Dart字串是UTF-16編碼的字元序列,可以使用單引號或者雙引號來建立字串:
    String str1 = '單引號字串';
    String str2 = "雙引號字串";
    
    print(str1);        //輸出:單引號字串
    print(str2);        //輸出:雙引號字串
    複製程式碼

9.2 單雙引號互相巢狀

  • String中單、雙引號互相巢狀情況如下所示
    String str1 = '單引號中的"雙引號"字串';
    String str2 = "雙引號中的'單引號'字串";
    
    print("yc-str1--" + str1);
    print("yc-str2--" + str2);
    
    //單引號裡面有單引號,必須在前面加反斜槓
    String str3 = '單引號中的\'單引號\'';
    String str4 = "雙引號裡面有雙引號,\"雙引號\"";
    print("yc-str3--" + str3);
    print("yc-str4--" + str4);
    複製程式碼
    • 列印值
    2019-06-21 17:52:07.722 16501-16583/com.hwmc.auth I/flutter: yc-str1--單引號中的"雙引號"字串
    2019-06-21 17:52:07.723 16501-16583/com.hwmc.auth I/flutter: yc-str2--雙引號中的'單引號'字串
    2019-06-21 17:52:07.723 16501-16583/com.hwmc.auth I/flutter: yc-str3--單引號中的'單引號'
    2019-06-21 17:52:07.723 16501-16583/com.hwmc.auth I/flutter: yc-str4--雙引號裡面有雙引號,"雙引號"
    複製程式碼
  • 注意點::
    • 單引號巢狀單引號之間不允許出現空串(不是空格),雙引號巢狀雙引號之間不允許出現空串:
    //String str5 = '單引號''''單引號';  //報錯了,逗比
    String str6 = '單引號'' ''單引號';
    String str7 = '單引號''*''單引號';
    String str8 = "雙引號"" ""雙引號";
    String str9 = "雙引號""*""雙引號";
    //String str10 = "雙引號""""雙引號";   //報錯了,逗比
    print("yc-str6--" + str6);
    print("yc-str7--" + str7);
    print("yc-str8--" + str8);
    print("yc-str9--" + str9);
    複製程式碼
  • 列印值
    2019-06-21 17:56:21.847 16501-16583/com.hwmc.auth I/flutter: yc-str6--單引號 單引號
    2019-06-21 17:56:21.847 16501-16583/com.hwmc.auth I/flutter: yc-str7--單引號*單引號
    2019-06-21 17:56:21.847 16501-16583/com.hwmc.auth I/flutter: yc-str8--雙引號 雙引號
    2019-06-21 17:56:21.847 16501-16583/com.hwmc.auth I/flutter: yc-str9--雙引號*雙引號
    複製程式碼

其他介紹

01.關於部落格彙總連結

02.關於我的部落格

部落格彙總專案開源地址:github.com/yangchong21…

相關文章