Flutter (二) Dart 語言基礎詳解 (異常,類,Mixin, 泛型,庫)

DevYK發表於2019-03-21

異常

Exception 型別

  • 延遲載入異常: DeferredLoadException

  • 格式異常 : FormatException

  • 整數除零異常: IntegerDivisionByZeroException

  • IO 異常 : IOException

  • 隔離產生異常: IsolateSpawnException

  • 超時異常 : TimeoutException

    /// 部分異常參考 跟 Java 型別的異常都大同小異
    main() {
      /// ---------------------------------異常的丟擲throw--------------------------------
      //丟擲Exception物件
    //  throw new FormatException('格式異常');
    
      //丟擲Error物件
    //  throw new NullThrownError();
    
      //丟擲任意非null物件
    //  throw '這是一個異常';
    
      /// ---------------------------------異常的捕獲try catch--------------------------------
      try {
    
        throw new NullThrownError();
    //    throw new OutOfMemoryError();
      } on OutOfMemoryError {
        //on 指定異常型別
        print('沒有記憶體了');
    //    rethrow; //把捕獲的異常給 重新丟擲
      } on Error {
        //捕獲Error型別
        print('Unknown error catched');
      } on Exception catch (e) {
        //捕獲Exception型別
        print('Unknown exception catched');
      } catch (e, s) {
        //catch() 可以帶有一個或者兩個引數, 第一個引數為丟擲的異常物件, 第二個為StackTrace物件堆疊資訊
        print(e);
        print(s);
      }
    }
    複製程式碼

Error 型別

  • 抽象類例項化錯誤 : AbstractClassInstantiationError

  • 引數錯誤 : ArgumentError

  • 斷言錯誤 : AssertionError

  • 非同步錯誤 : AsyncError

  • Cast 錯誤 : CastError

  • 併發修改錯誤 : ConcurrentModificationError

  • 週期初始錯誤 : CyclicInitializationError

  • Fall Through 錯誤 : FallThroughError

  • json 不支援錯誤 : JsonUnsupportedObjectError

  • 沒有這個方法錯誤 : NoSuchMethodError

  • Null 錯誤 : NullThrownError

  • 記憶體溢位錯誤 : OutOfMemoryError

  • 遠端錯誤 : RemoteError

  • 堆疊溢位錯誤 : StackOverflowError

  • 狀態錯誤 : StateError

  • 未實現的錯誤 : UnimplementedError

  • 不支援錯誤 : UnsupportedError

建構函式

  • 普通建構函式(Java / Dart 比較 )

    void main(){
         //普通建構函式
      var p = new Point(1, 1); //new 可省略 var point = Point(1, 2);
      print(p);
    //  print(p.runtimeType); //可以使用Object類的runtimeType屬性,獲取物件的型別
    }
    
    class Point {
      num x;
      num y;
        
      //普通建構函式 Java 形式
    //  Point(num x, num y){
    //    this.x = x;
    //    this.y = y;
    //  }
        
      //簡化構造 Dart 形式
    //  Point(this.x, this.y);
    
    
      @override
      String toString() {
        // TODO: implement toString
        return 'Point(x = $x, y = $y)';
      }
    }
    
    複製程式碼
  • 命名建構函式

    void main(){
          /// 命名建構函式
     var p =  Point.fromJson({'x':2,'y':3});
      print(p);
    }
    
    /// 建立一個 Point 類
    class Point {
      num x;
      num y;
    
      //命名建構函式
      Point.fromJson(Map json){
        x = json['x'];
        y = json['y'];
      }
    
      @override
      String toString() {
        return 'Point{x: $x, y: $y}';
      }
    }
    複製程式碼
  • 重定向建構函式

    void main(){
      Point  p = Point.alongXAxis(2);
      print(p);
    }
    
    class Point {
      num x;
      num y;
    
      //簡化構造
      Point(this.x, this.y);
    
      //重定向建構函式,使用冒號呼叫其它建構函式
      Point.alongXAxis(num x) : this(x, 0);
    
      @override
      String toString() {
        return 'Point{x: $x, y: $y}';
      }
    }
    複製程式碼
  • 初始化列表

    void  main(){
        var p = Point(3,3);
        print(p);
        
        /// 列印結果:Point{x: 3, y: 3,distanceFromOrigin:3.0}
    }
    
    /// 建立一個 Point 類
    class Point {
      num x;
      num y;
      var distanceFromOrigin;
    
      //初始化列表  這裡的 sqrt 開方需要導包 import 'dart:math';
      Point(this.x,this.y) : distanceFromOrigin = sqrt(x*y);
    
      @override
      String toString() {
        return 'Point{x: $x, y: $y,distanceFromOrigin:${distanceFromOrigin}';
      }
    }
    複製程式碼
  • 呼叫超類建構函式

    void main(){
     var child =  Child.fromJson(5, 5);
     var child2 =  Child(5,6);
     print('child: ${child} ,child2: ${child2}');
        
     //列印結果,由此可見跟 Java 一樣 父類方法先執行。
     ///超類命名建構函式
     ///子類命名建構函式
     ///超類命名建構函式
    }
    
    ///建立一個父類
    class Parent{
      num x;
      num y;
      
      Parent.fromJson(x,y):x = x,y = y{
        print('超類命名建構函式');
      }
    }
    
    ///建立一個子類
    class Child extends Parent{
      num x;
      num y;
    
    /*  //如果超類沒有預設建構函式, 則你需要手動的呼叫超類的其他建構函式
      Child.fromJson(x, y) : super.fromJson(x, y){
        //呼叫超類建構函式的引數無法訪問 this
        print('子類建構函式');
      }*/
        
      Child(this.x,this.y) : super.fromJson(x, y);
    
      //在建構函式的初始化列表中使用 super(),需要把它放到最後
      Child.fromJson(x,y) : x = x,y = y,super.fromJson(x,y){
        print('子類命名建構函式');
      } 
    }
    複製程式碼
  • 常量建構函式

    /// 注意:同一個物件如果定義為常量物件的話,那麼存在記憶體中的地址是相同的
    void main(){
      var p2 = const Point2(6, 8);
      print(p2);
    
      var p21 =  Point2(4, 4); //建立的是非 常量物件
      var p22 = const Point2(4, 4);
      print(identical(p22, p21));
      print(identical(p2, p22));
    }
    
    ///建立一個常量的建構函式
    class Point2 {
      //定義 const 建構函式要確保所有例項變數都是final
      final num x;
      final num y;
      static final Point2 origin = const Point2(0, 0);
    
      //const 關鍵字放在建構函式名稱之前,不能有函式體
      const Point2(this.x, this.y);
    
      @override
      String toString() {
        return 'Point2{x: $x, y: $y}';
      }
    }
    複製程式碼
  • 工廠建構函式

    void main(){
      /// 工廠方法建構函式
      var singletonl = Singleton('Java');
      var singletonl2 = Singleton('Flutter');
      print(identical(singletonl, singletonl2));
    }
    
    ///建立一個工廠模式的類
    ///第一種方試
    class Singleton{
      String name;
      //工廠建構函式無法訪問 this.所以這裡要靜態的
      static Singleton _cache;
      factory Singleton([String name = 'singleton']){
        if(_cache == null){
          _cache = Singleton._newObject(name);
        }
        return _cache;
      }
    
      Singleton._newObject(this.name);
    }
    
    /// 第二種方式
    class Singleton{
        String name;
        static Singleton _cache;
        
        factory Singleton([String name = 'singleton']) => _cache ?== Singleton._newObject(name);
        
      	Singleton._newObject(this.name);
    }
    
    複製程式碼
  • 工廠模式兩種方式

    • 建立頂級函式

      void main(){
        var footMassage = new Massage('foot');
        footMassage.doMassage();
        var bodyMassage = new Massage('body');
        bodyMassage.doMassage();
        var specialMassage = new Massage('%#@##@##');
        specialMassage.doMassage();
          
        //列印:
        //腳底按摩
        //全身按摩
        //特殊按摩
      }
      
      /工廠模式
      abstract class Massage {
        factory Massage(String type) {
          switch (type) {
            case 'foot':
              return new FootMassage();
            case 'body':
              return new BodyMassage();
            default:
              return new SpecialMassage();
          }
        }
      
        void doMassage();
      }
      
      class FootMassage implements Massage {
        @override
        doMassage() {
          print('腳底按摩');
        }
      }
      
      class BodyMassage implements Massage {
        @override
        void doMassage() {
          print('全身按摩');
        }
      }
      
      class SpecialMassage implements Massage {
        @override
        void doMassage() {
          print('特殊按摩');
        }
      }
      
      複製程式碼
    • 建立工廠建構函式

      void main(){
        ///建立頂級函式
        var footMassage = massageFactory('foot');
        footMassage.doMassage();
      }
      
      //工廠函式
      class Massage {
        void doMassage() {
          print('按摩');
        }
      }
      /**
       * 建立頂級工廠模式
       */
      Massage massageFactory(String type) {
        switch (type) {
          case 'foot':
            return FootMassage();
          case 'body':
            return BodyMassage();
          default:
            return SpecialMassage();
        }
      }
      
      class FootMassage extends Massage {
        @override
        doMassage() {
          print('腳底按摩');
        }
      }
      
      class BodyMassage extends Massage {
        @override
        void doMassage() {
          print('全身按摩');
        }
      }
      
      class SpecialMassage extends Massage {
        @override
        void doMassage() {
          print('特殊按摩');
        }
      }
      複製程式碼
  • set,get

    void main(){
      ///set get
      var rect = new Rectangle(1, 1, 10, 10);
      print(rect.left);
      rect.right = 12;
      print(rect.left);
      rect.buttom = 11;
      print(rect.top);
        
      ///列印效果
      /// 1,2,1 
    }
    
    /**
     * setter getter
     * 每個例項變數都隱含的具有一個 getter, 如果變數不是 final 的則還有一個 setter
     * 可以通過實行 getter 和 setter 來建立新的屬性, 使用 get 和 set 關鍵字定義 getter 和 	
     * setter
     */
    class Rectangle {
      num left;
      num top;
      num width;
      num height;
    
      //宣告構造方法
      Rectangle(this.left, this.top, this.width, this.height);
    
      // getter 和 setter 的好處是,可以開始使用例項變數,
      // 後面可以把例項變數用函式包裹起來,
      // 而呼叫你程式碼的地方不需要修改。
      //獲取 right
      num get right => left + width;
    
      //set right
      set right(num value) => left = value - width;
    
      //獲取 button
      num get button => top + height;
    
      //set button
      set buttom(num value) => top = value - height;
    }
    複製程式碼
  • 可呼叫類

    void main(){
      var cf = new ClassFunction();
      var out = cf("Java"," Android"," Flutter");
      print('$out'); // Hi there, gang!
      print(cf.runtimeType); // ClassFunction
      print(out.runtimeType); // String
      print(cf is Function); // true
    }
    
    /**建立一個可呼叫的類*/
    class ClassFunction {
      call(String a, String b, String c) => '$a $b $c';
    }
    複製程式碼
  • 過載

    void main(){
      final v1 = Vector(2, 3);
      final v2 = Vector(2, 2);
      final r1 = v1 + v2;
      final r2 = v1 - v2;
      print([r1.x, r1.y]);
      print([r2.x, r2.y]);
    }
    
    //過載操作類
    class Vector{
      final int x;
      final int y;
    
      const Vector(this.x,this.y);
    
      //過載+
      Vector operator + (Vector v){
        return Vector(x+v.x, y+v.y);
      }
      //過載-
      Vector operator -(Vector v) {
        return new Vector(x - v.x, y - v.y);
      }
    }
    複製程式碼

Mixin

  • 1553157226(1).jpg

  • 程式碼

    void main() {
      Bicycle().transport();
      Motorcycle().transport();
      Car().transport();
      //四輪木製腳踏車
      WoodenCar().transport();
        
      /// 列印內容
      自行車:
      動力元件: 兩個輪子 , 安全指數: low , 動力來源:全靠腿登
      摩托車:
      動力元件: 兩個輪子 , 安全指數: low , 動力來源:汽油
      汽車:
      動力元件: 四個輪子 , 安全指數: middle , 動力來源:汽油
      四輪木製腳踏車:
      動力元件: 四個輪子 , 安全指數: middle , 動力來源:汽油
    }
    
    
    //交通工具類,擁有運輸功能
    abstract class Transportation {
      //運輸功能
      void transport();
    }
    
    //雙輪交通工具
    class TwoWheelTransportation {
      String powerUnit() => "兩個輪子";
    }
    
    //四輪交通工具,一般來說安全效能為中
    class FourWheelTransportation {
      String powerUnit() => "四個輪子";
    }
    
    //安全指數中等的交通工具
    class MiddleSafetyIndex {
      String safetyIndex() => "middle";
    }
    
    //安全指數低的交通工具
    class LowSafetyIndex {
      String safetyIndex() => "low";
    }
    
    //人力發動機
    class BodyEnergyTransportation {
      String energy() => "全靠腿登";
    }
    
    //汽油能源交通工具
    class GasolineEnergyTransportation {
      String energy() => "汽油";
    }
    
    //自行車
    class Bicycle extends Transportation
        with TwoWheelTransportation, LowSafetyIndex, BodyEnergyTransportation {
      @override
      void transport() {
        print(
            "自行車:\n動力元件: ${powerUnit()} , 安全指數: ${safetyIndex()} , 動力來源:${energy()}");
      }
    }
    
    //摩托車
    class Motorcycle extends Transportation
        with TwoWheelTransportation, LowSafetyIndex, GasolineEnergyTransportation {
      @override
      void transport() {
        print(
            "摩托車:\n動力元件: ${powerUnit()} , 安全指數: ${safetyIndex()} , 動力來源:${energy()}");
      }
    }
    
    //汽車
    class Car extends Transportation
        with
            FourWheelTransportation,
            MiddleSafetyIndex,
            GasolineEnergyTransportation {
      @override
      void transport() {
        print(
            "汽車:\n動力元件: ${powerUnit()} , 安全指數: ${safetyIndex()} , 動力來源:${energy()}");
      }
    }
    
    //四輪木製腳踏車
    class WoodenCar extends Car
    {
      @override
      void transport() {
        print(
            "四輪木製腳踏車:\n動力元件: ${powerUnit()} , 安全指數: ${safetyIndex()} , 動力來源:${energy()}");
      }
    }
    
    
    複製程式碼
  • 總結

    注意 extends ,with 順序問題:

    1. 如果 2 個或多個超類擁有相同簽名的 A 方法,那麼子類會以繼承的最後一個超類中的 A 方法為準。
    2. 當然這是子類沒有重寫 A 方法的前提下,如果子類自己重寫了 A 方法則以本身的 A 方法為準。

    程式碼演示:

    void main(){
      var ab = AB();
      var ba = BA();
      var c = C();
      var cc = CC();
    
      print(ab.getMessage());
      print(ba.getMessage());
      print(c.getMessage());
      print(cc.getMessage());
      
        
      ///列印 B,A,C,B
    }
    
    class A {
      String getMessage() => 'A';
    }
    
    class B {
      String getMessage() => 'B';
    }
    
    class P {
      String getMessage() => 'P';
    }
    
    class AB extends P with A, B {}
    
    class BA extends P with B, A {}
    
    class C extends P with B, A {
      String getMessage() => 'C'; //優先順序最高的是在具體類中的方法。
    }
    
    class CC extends P with B implements A {
    } //這裡的 implement 只是表明要實現 A 的方法,這個時候具體實現是再 B 中 mixin 了具體實現
    複製程式碼

泛型

  • 容器型別的泛型,使用方式跟 Java 一樣。

    void main(){
      ///使用泛型,很多的容器物件,在建立物件時都可以定義泛型型別,跟Java 一樣
      var list = List<String>();
      list.add('1');
      list.add('2');
      list.add('4');
      print(list);
    
      /// Map 泛型 跟 Java 也都是一樣
      var map = Map<int, String>();
      map[0] = '23';
      map[55] = '33';
      print(map);
    }
    複製程式碼
  • 泛型函式

    void main(){
       //泛型函式
      K addCache<K, V>(K key, V value) {
        K temp = key;
        print('key:$key ,value: $value');
        return temp;
      }
    
      var key  = addCache(5, '5');
      print(key);
      print(key.runtimeType);
    }
    複製程式碼
  • 建構函式泛型

    void main(){
      //建構函式泛型
      var p = Phone<String>('Flutter');
      print(p.text);
    }
    
    class Phone<T> {
      final T text;
      Phone(this.text);
    }
    複製程式碼
  • 泛型限制

    void main(){
      //泛型限制, 通過 extends 關鍵字限定可泛型使用的型別
      var footMassage = FootMassage();
      var m = Massage<FootMassage>(footMassage);
      m.massage.doMassage();
    }
    
    //泛型限制
    class Massage<T extends FootMassage > {
      final T massage;
      Massage(this.massage);
    }
    
    class FootMassage {
      void doMassage() {
        print('腳底按摩');
      }
    }
    
    複製程式碼
  • 執行時判斷泛型

    void main(){
      //執行時可判斷泛型
      var names = List<String>();
      print(names is List<String>);
      print(names.runtimeType);   
    }
    複製程式碼
  • Dart 泛型 與 Java 區別

    1. Java 中的泛型資訊是編譯時的,泛型資訊在執行時是不存在的。
    2. Dart 的泛型型別是固化的,在執行時也有可以判斷的具體型別。

  • 使用核心庫

    import 'dart:math'; //載入核心庫
    void main(){
        print(sqrt(4));
    }
    複製程式碼
  • 載入網路請求第三方庫(pub.dartlang.org/packages?q=…)

    1. 編寫 pubspec.yaml
        
        dependencies:
      flutter:
        sdk: flutter
    
      cupertino_icons: ^0.1.0
      dio: ^2.1.0
      
    2. 程式碼編寫
          import 'package:dio/dio.dart';
          void main(){
          gethttp();
      }
    
    void getHttp() async{
      try{
        var response = await Dio().get("http://www.baidu.com");
        print(response);
      }catch(e){
        print(e);
      }
    
    }
    
    複製程式碼
  • 載入檔案

    1. 新建立一個 MyLib1.dart 檔案
        class DevFlutter {
    
      static DevFlutter _deFlutter;
    
      factory DevFlutter () => _deFlutter ??= DevFlutter._newInstance();
    
      DevFlutter._newInstance();
    
    }
    
    class Test {
      void start() {
        print(" Flutter... ");
      }
    }
    
    2. 回到 A dart 檔案 匯入 MyLib1.dart 包
        import 'Mylib1.dart'
        void main(){
        //載入檔案
        var myLib1 = MyLib();
    }
        
    複製程式碼
  • 指定庫字首

    ///注意:如果兩個庫有衝突的識別符號,可以為其中一個或兩個庫都指定字首:
    import 'MyLib1.dart' as lib1; 
    import 'MyLib2.dart' as lib2;
    
    void main(){
     var myLib = lib1.MyLib();
     var myLib2 = lib2.MyLib();    
    }
    複製程式碼
  • 選擇性載入

    1. show 只載入庫的某些部分
    2. hide 篩選掉庫的某些部分
    import 'Mylib1.dart' as lib1 show Test;
    import 'Mylib2.dart' as lib2 hide Test;
    
    void main(){
     	var test = lib1.Test();
    	var lib = lib2.MyLib();
    }
    複製程式碼
  • 延遲載入

    1. 使用 deferred as 匯入
    2. 使用識別符號呼叫 loadLibrary() 載入庫;
    import 'MyLib1.dart' deferred as defelib;//延遲載入
    
    void main(){
      //延遲載入
      deferredLoad();
    }
    
    //延遲載入
    //可提高程式啟動速度
    //用在不常使用的功能
    //用在載入時間過長的包
    void deferredLoad() async{
      await defelib.loadLibrary();
      var test = defelib.Test;
    }
    複製程式碼
  • 自定義庫

    1. 建立一個 A 庫 a .dart
    2. 建立一個 B 庫 b.dart
    3. 建立一個 lib 庫 libs.dart

    注意:程式碼中的 part,library 的含義

    part: 有的時候一個庫可能太大,不能方便的儲存在一個檔案當中。Dart 允許我們把一個庫拆分成一個或者多個較小的 part 元件。或者我們想讓某一些庫共享它們的私有物件的時候,我們需要使用 part 。

    library: 當沒有指定 library 指令的時候,根據每個庫 的路徑和檔名會為每個庫生成一個唯一的標籤。 所以,我們 建議你不要在程式碼中使用 library 指令, 除非你想 生成庫的 API 文件

    1. a.dart。
    part of libs;
    
    void printA() => print('A');
    
    2. b.dart。
    part of libs;
    
    void printB() => print('B');
    
    3. libs 庫
    library libs;
    
    part 'util.dart';
    
    part 'tool.dart';
    
    void printLibs() => print('libs');
    
    ///開始呼叫
    //import 'lib/libs.dart';//載入自定義庫
    
    void main(){
        //載入自定義庫
        printA();
        printB();
        printLibs();
    }
    
    
        
    複製程式碼

感謝

Dart 語法學習官網;

相關文章