<Dart基礎(chǔ)>Dart語(yǔ)法(下)

前文鏈接:

內(nèi)容:

  • 函數(shù)(方法)
    函數(shù)定義及各類函數(shù)通熄;函數(shù)參數(shù)耙旦;閉包
  • 面向?qū)ο?br> 定義脱羡;構(gòu)造函數(shù);成員(變量與函數(shù))
    繼承與多態(tài)免都;抽象類锉罐;接口;枚舉類
    Mixins绕娘;操作符
  • 泛型
    定義脓规;用法;限制泛型類型
  • 庫(kù)和可見(jiàn)性
  • 異常
  • 元數(shù)據(jù)

五险领、函數(shù)(方法)

1侨舆、說(shuō)明:

  • Dart 是一個(gè)真正的面向?qū)ο笳Z(yǔ)言,方法也是對(duì)象并且具有一種類型绢陌, Function态罪。

  • 這意味著,方法可以賦值給變量下面,也可以當(dāng)做其他方法的參數(shù)。也可以把 Dart 類的實(shí)例當(dāng)做方法來(lái)調(diào)用绩聘。 詳情請(qǐng)參考 Callable classes沥割。

  • 方法都有返回值,當(dāng)沒(méi)有指定返回值的時(shí)候凿菩,函數(shù)返回null机杜,即最后默認(rèn)執(zhí)行一句return null,可以省略不寫(xiě)衅谷。

2椒拗、函數(shù)定義及各類函數(shù):

  • 基本形式:

    返回值 方法名(參數(shù)1, 參數(shù)2, ...) {
      方法體
      return 返回值;
    }
    

    示例:

    int sum(int a, int b) {
      return a + b;
    }
    
  • 省略模式:
    1、定義方法的返回值類型參數(shù) 都可以省略

    sum(a, b) {
      return a + b;
    }
    
    //sumResult = 9
    print("sumResult = ${sum(3, 6)}");
    

    說(shuō)明:建議明確方法(函數(shù))的輸入類型和返回值類型,既便于修改蚀苛,也方便閱讀在验。重要的是,如果不寫(xiě)方法參數(shù)輸入類型堵未,則在調(diào)用的時(shí)候腋舌,調(diào)用者可能無(wú)法明確參數(shù)類型(經(jīng)測(cè)試,在編譯階段并未有相應(yīng)的參數(shù)類型的檢查提示)渗蟹,這就可能導(dǎo)致Unhandled exception之類的錯(cuò)誤块饺。

  • 箭頭函數(shù):
    1、語(yǔ)法:=> expr
    2雌芽、是 { return expr; } 形式的縮寫(xiě)授艰。=> 形式 有時(shí)候也稱之為 胖箭頭 語(yǔ)法。
    注:只適用于一個(gè)表達(dá)式的方法世落。
    3淮腾、示例:

    int sum(int a, int b) => a + b;
    
  • 匿名函數(shù):
    1、沒(méi)有名字的函數(shù)岛心,稱之為匿名函數(shù)来破,有時(shí)候也被稱為lambda 或者 closure 閉包
    2忘古、你可以把匿名函數(shù)賦值給一個(gè)變量徘禁, 然后你可以通過(guò)這個(gè)變量使用這個(gè)函數(shù)。
    3髓堪、匿名函數(shù)和命名函數(shù)看起來(lái)類似送朱,在括號(hào)之間可以定義一些參數(shù),參數(shù)使用逗號(hào)分割干旁,也可以是可選參數(shù)驶沼,大括號(hào)中的代碼為函數(shù)體。

    • 定義:
      ([[Type] param1[, …]]) { 
        codeBlock; 
      };
      
    • 示例:
      Function sum = (int a, int b)
           {
             return a + b;
           };
      //sum = 9
      print("sum = ${sum(3, 6)}");
      
      var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums'];
      //其中forEach接收一個(gè)函數(shù)
      list.forEach((i) => print(list.indexOf(i).toString() + ': ' + i));
      
  • 入口函數(shù):
    1争群、每個(gè)應(yīng)用都需要有個(gè)頂級(jí)的 main() 入口方法才能執(zhí)行回怜。 main() 方法的返回值為 void 并且有個(gè)可選的 List<String> 參數(shù)。

    void main(List<String> args) {
       print(arguments);
    }
    

    通過(guò)命令行可以將參數(shù)打印出來(lái):

    入口函數(shù)調(diào)用

    說(shuō)明:其中使用dart 命令調(diào)用换薄,參數(shù)用空格隔開(kāi)

  • 函數(shù)別名
    1玉雾、在 Dart 語(yǔ)言中,方法也是對(duì)象轻要。
    2复旬、使用 typedef, 或者 function-type alias 來(lái)為方法類型命名, 然后可以使用命名的方法冲泥。
    3驹碍、當(dāng)把方法類型賦值給一個(gè)變量的時(shí)候壁涎,typedef 保留類型信息。

    • 看下面一個(gè)簡(jiǎn)單的例子:
    typedef int compare(int a, int b);
    
    int sort(int a, int b) {
      return a - b;
    }
    
    void main(List<String> args) {
      //(int, int) => int
      print(compare);
      //Closure: (int, int) => int from Function 'sort': static.
      print(sort);
      //true
      print(sort is Function);
      //true
      print(sort is compare);
    }
    

    說(shuō)明:通過(guò)is 操作符可以判斷兩個(gè)對(duì)象是否相等志秃。

    • 看下面的例子:
      下面的代碼沒(méi)有使用 typedef:
    class SortedCollection {
      Function compare;
    
      SortedCollection(int f(Object a, Object b)) {
        compare = f;
      }
    }
    
     // Initial, broken implementation.
     int sort(Object a, Object b) => 0;
    
    main() {
      SortedCollection coll = new SortedCollection(sort);
    
      // 我們只知道 compare 是一個(gè) Function 類型怔球,
      // 但是不知道具體是何種 Function 類型?
      assert(coll.compare is Function);
    }
    

    說(shuō)明:當(dāng)把 f 賦值給 compare 的時(shí)候洽损, 類型信息丟失了庞溜。 f 的類型是 (Object, Object) → int (這里 → 代表返回值類型), 當(dāng)然該類型是一個(gè) Function碑定。
    如果我們使用顯式的名字并保留類型信息流码, 開(kāi)發(fā)者和工具可以使用 這些信息:

    typedef int Compare(Object a, Object b);
    
    class SortedCollection {
      Compare compare;
    
      SortedCollection(this.compare);
    }
    
     // Initial, broken implementation.
     int sort(Object a, Object b) => 0;
    
    main() {
      SortedCollection coll = new SortedCollection(sort);
      assert(coll.compare is Function);
      assert(coll.compare is Compare);
    }
    
    • 注意: 目前,typedefs 只能使用在 function 類型上延刘,但是將來(lái) 可能會(huì)有變化漫试。

3、函數(shù)參數(shù)

  • 靜態(tài)作用域
    1碘赖、Dart 是靜態(tài)作用域語(yǔ)言驾荣,變量的作用域在寫(xiě)代碼的時(shí)候就確定過(guò)了。
    2普泡、基本上大括號(hào)里面定義的變量就 只能在大括號(hào)里面訪問(wèn)播掷,和 Java 作用域 類似。

    var topLevel = true;
    
    main() {
        var insideMain = true;
    
        myFunction() {
            var insideFunction = true;
    
            nestedFunction() {
                var insideNestedFunction = true;
    
                print(topLevel);  //true
                print(insideMain);  //true
                print(insideFunction);  //true
                print(insideNestedFunction);  //true
            }
            
            //undefined name 'insideNestedFunction'
            //print(insideNestedFunction);
            
            nestedFunction();
        }
        
        //undefined name 'insideFunction'
        //print(insideFunction);
    
        myFunction();
    }
    
  • 可選參數(shù)
    1.可選參數(shù)包括:可選命名參數(shù)可選位置參數(shù)
    2.但是這兩種參數(shù)不能同時(shí)當(dāng)做可選參數(shù)撼班。
    3.可選參數(shù)的方法歧匈,在調(diào)用的時(shí)候,是可選的砰嘁,可傳入可不傳入
    4.可選參數(shù)只能放到方法參數(shù)的末尾件炉,不能放到必需參數(shù)的前面

    • 可選命名參數(shù):
      定義方法時(shí),可選命名參數(shù)需要將可選的參數(shù)放到{}
      調(diào)用方法時(shí)矮湘,方法中的參數(shù)可以通過(guò)這種形式 paramName: value 來(lái)指定命名參數(shù)
       main() {
           //name:張三斟冕;isMan:null;age:null
           printArgs("張三");
           //name:李四缅阳;isMan:false磕蛇;age:null
           printArgs("李四", isMan: false);
           //name:王五;isMan:null十办;age:88
           printArgs("王五", age: 88);
           //name:趙六孤里;isMan:true;age:55
           printArgs("趙六", isMan: true, age: 55);
       }
       
       void printArgs(String name, {bool isMan, int age}) {
           print("name:$name橘洞;isMan:$isMan;age:$age");
       }
    
    • 可選位置參數(shù):
      定義方法時(shí)说搅,可選位置參數(shù)需要將可選的參數(shù)放到[]
      調(diào)用方法時(shí)炸枣,方法中的參數(shù)根據(jù)位置來(lái)指定命名參數(shù)
       main() {
           //name:張三;isMan:null;age:null
           printArg("張三");
           //name:李四适肠;isMan:true霍衫;age:null
           printArg("李四", true);
           //無(wú)法調(diào)用
           //printArg("王五", 29);
           //name:趙六;isMan:true侯养;age:29
           printArg("趙六", true, 29);
       }
       
       void printArg(String name, [bool isMan, int age]) {
           print("name:$name敦跌;isMan:$isMan;age:$age");
       }
    
  • 默認(rèn)參數(shù)值
    1逛揩、在定義方法的時(shí)候柠傍,可以使用 = 來(lái)定義可選參數(shù)的默認(rèn)值。
    2辩稽、默認(rèn)值只能是編譯時(shí)常量惧笛。
    3、如果沒(méi)有提供默認(rèn)值逞泄,則默認(rèn)值為 null患整。

    void main() {
      //name:張三;age:39喷众;isMain:true
      printArgs("張三", 39);
      //name:Lili各谚;age:33;isMain:false
      printArgs("Lili", 33, isMan: false);
    }
    
    void printArgs(String name, int age, { bool isMan=true }) {
      print("name:$name到千;age:$age昌渤;isMain:$isMan");
    }
    
  • 測(cè)試函數(shù)是否相等
    下面是測(cè)試頂級(jí)方法、靜態(tài)函數(shù)和實(shí)例函數(shù) 相等的示例:

       foo() {}               // 一個(gè)頂級(jí)方法
       
       class A {
           static void bar() {} // 一個(gè)靜態(tài)方法
           void baz() {}        // 一個(gè)實(shí)例方法
       }
       
       main() {
           var x;
       
           // 比較 頂級(jí)方法.
           x = foo;
           print(foo == x);
       
           // 比較靜態(tài)方法
           x = A.bar;
           print(A.bar == x);
       
           // 比較實(shí)例方法
           var v = new A(); // A的第一個(gè)實(shí)例#1
           var w = new A(); // A的第二個(gè)實(shí)例#2
           var y = w;
           x = w.baz;
       
           // 這些閉包引用同一個(gè)實(shí)例(#2)父阻,因此它們是相等的
           print(y.baz == x);
       
           // 這些閉包引用不同的實(shí)例愈涩,因此它們不等
           print(v.baz != w.baz);
       }
    

4、閉包

  • 特性:
    1加矛、一個(gè) 閉包 是一個(gè)方法對(duì)象履婉。
    2、閉包定義在其他方法的內(nèi)部斟览,一般通過(guò)return將其作為返回值返回毁腿。
    3、不管閉包對(duì)象(方法返回的)在何處被調(diào)用苛茂,該對(duì)象都可以訪問(wèn)其(即閉包所在的方法)作用域內(nèi)的變量已烤,并持有其狀態(tài)。

  • 示例:

    void test() {
        Function add = makeAdder(1);
        int result = add(2);
        //result = 3
        print("result = $result");
    }
    
    /**
     * 定義返回方法的函數(shù)
     */
    Function makeAdder(num outerNum) {
        return (num innerNum)=> outerNum + innerNum;
    }
    
  • 一段有意思的代碼:

       void main() {
           var callbacks = [];
       
           for (var i = 0; i < 3; i++) {
               // 在列表 callbacks 中添加一個(gè)函數(shù)對(duì)象妓羊,這個(gè)函數(shù)會(huì)記住 for 循環(huán)中當(dāng)前 i 的值胯究。
               callbacks.add(() => print('Save $i'));
           }
           //[Closure: () => void, Closure: () => void, Closure: () => void]
           print(callbacks);
           callbacks.forEach((c) => c()); // 分別輸出 Save 0 1 2
       }
    

    說(shuō)明:

    • for 循環(huán)中,向callbacks 中加入的是一個(gè)匿名函數(shù)(此處定義的匿名函數(shù)的作用是打印局部變量i)躁绸,此函數(shù)持有循環(huán)中的變量i(一般的裕循,i作為局部變量臣嚣,循環(huán)結(jié)束就被回收了),即閉包的特性(持有外部方法中變量的狀態(tài))剥哑。
    • forEach 函數(shù)接收的是一個(gè)函數(shù)對(duì)象(匿名函數(shù):(c) => c())作為參數(shù)硅则,每次循環(huán)進(jìn)行調(diào)用此函數(shù),即為callbacks 數(shù)組中的函數(shù)對(duì)象株婴。

六怎虫、面向?qū)ο?/h1>

1、定義

  • Dart 是一個(gè)面向?qū)ο缶幊陶Z(yǔ)言困介,同時(shí)支持基于 mixin 的繼承機(jī)制大审。
  • 每個(gè)對(duì)象都是一個(gè)類的實(shí)例,所有的類都繼承于 Object逻翁。
  • 基于 Mixin 的繼承 意味著每個(gè)類(Object 除外) 都只有一個(gè)超類饥努,一個(gè)類的代碼可以在其他多個(gè)類繼承中重復(fù)使用。即一個(gè)類可以繼承自多個(gè)父類八回。
  • 使用關(guān)鍵字calss 聲明一個(gè)類
  • 使用關(guān)鍵字new 創(chuàng)建一個(gè)對(duì)象酷愧,new 可以省略。
  • 對(duì)象的成員包括方法和數(shù)據(jù) (函數(shù) 和 實(shí)例變量)缠诅。
  • 示例:
       class Person {
       }
       
       void main() {
           Person p = new Person();
           
           //省略new關(guān)鍵字
           Person pp = Person();
       }
    

2溶浴、構(gòu)造函數(shù)

  • 定義:
    1、定義一個(gè)和類名字一樣的方法就定義了一個(gè)構(gòu)造函數(shù)管引。
    2士败、還可以帶有其他可選的標(biāo)識(shí)符,形如ClassName.identifier褥伴。

       class Person {
           Person() {
               print("person===super");
           }
       }
       
       class Student extends Person {  //這里是繼承父類谅将,后面會(huì)總結(jié)
           Student() {
               print("student====this");
           }
       }
       
       void main() {
           Student s = Student();
    
           //打印結(jié)果:
           //person===super
           //student====this
       }
    
  • 默認(rèn)構(gòu)造函數(shù)
    1、如果未顯式定義構(gòu)造函數(shù)重慢,會(huì)默認(rèn)一個(gè)空的構(gòu)造函數(shù)饥臂。
    2、默認(rèn)構(gòu)造函數(shù)沒(méi)有參數(shù)似踱,并且會(huì)調(diào)用超類的沒(méi)有參數(shù)的構(gòu)造函數(shù)隅熙。

       class Person {
           Person() {
               print("person===super");
           }
       }
    
       class Student extends Person {  //這里是繼承父類,后面會(huì)總結(jié)
       }
       
       void main() {
           Student s = Student();
    
           //打印結(jié)果:
           //person===super
       }
    
  • 自定義構(gòu)造函數(shù)
    1核芽、如果存在自定義構(gòu)造函數(shù)囚戚,則默認(rèn)構(gòu)造函數(shù)無(wú)效,即只能存在一個(gè)構(gòu)造函數(shù)(這也驗(yàn)證了函數(shù)不能重載的特性)轧简。
    2驰坊、其中this 關(guān)鍵字指當(dāng)前的實(shí)例。

       class Person {
       
           String name;
           int age;
       
           Person(String name, int age) {
               this.name = name;
               this.age = age;
           }
           
           //報(bào)錯(cuò):The default constructor is already defined.
           Person() {
               print("person===super");
           }
       }
    
  • 語(yǔ)法糖
    1哮独、由于把構(gòu)造函數(shù)參數(shù)賦值給實(shí)例變量的場(chǎng)景太常見(jiàn)了庐橙, Dart 提供了一個(gè)語(yǔ)法糖來(lái)簡(jiǎn)化這個(gè)操作:

       class Person {
       
           String name;
           int age;
       
           /*
           //常規(guī)寫(xiě)法
           Person(String name, int age) {
               this.name = name;
               this.age = age;
           }*/
           
           //語(yǔ)法糖寫(xiě)法
           Person(this.name, this.age);
       
       }
    
  • 命名構(gòu)造函數(shù)

    • 說(shuō)明:
      1假勿、使用命名構(gòu)造函數(shù)可以為一個(gè)類實(shí)現(xiàn)多個(gè)構(gòu)造函數(shù)
      2、使用命名構(gòu)造函數(shù)來(lái)更清晰的表明你的意圖
      3态鳖、構(gòu)造函數(shù)不能繼承,所以超類的命名構(gòu)造函數(shù)也不會(huì)被繼承恶导。
    • 實(shí)現(xiàn)方式:類名.方法浆竭。其中方法名稱可以自定義
    • 示例:
      class Person {
      
          String name;
          int age;
      
          //語(yǔ)法糖寫(xiě)法
          Person(this.name, this.age);
      
          //fromName名稱可以隨便起名
          Person.fromName(String name) {
              this.name = name;
          }
      
         //withAge名稱可以隨便起名      
          Person.withAge(int age) {
              this.age = age;
          }
      
          void printArgs() {
              print("name:$name;age:$age");
          }
      
      }
      
      void main() {
          Person p = Person("張三", 18);
          //name:張三惨寿;age:18
          p.printArgs();
      
          Person pp = Person.fromName("李四");
          //name:李四邦泄;age:null
          pp.printArgs();
      
          Person ppp = Person.withAge(33);
          //name:null;age:33
          ppp.printArgs();
      }
      
  • 常量構(gòu)造函數(shù)

    • 說(shuō)明:
      1裂垦、使用常量構(gòu)造函數(shù)可以創(chuàng)建編譯時(shí)常量顺囊,即類是不可變狀態(tài)。
      2蕉拢、使用const 聲明構(gòu)造方法特碳,并且所有變量都為final
      3晕换、要使用常量構(gòu)造函數(shù)只需要用 const 替代 new 即可午乓,也可以省略const
      4闸准、兩個(gè)一樣的編譯時(shí)常量其實(shí)是 同一個(gè)對(duì)象(通過(guò)identical可進(jìn)行對(duì)比)益愈。
    • 示例:
      class Person {
          final String name;
      
          final int age;
      
          const Person(this.name, this.age);
      
          void printArgs() {
              print("name:$name;age:$age");
          }
      }
      
      void main() {
          const p = const Person("張三", 33);
          const pp = const Person("張三", 33);
      
          //true
          print(identical(p, pp));  //比較兩個(gè)對(duì)象是否相等
      
      }
      
  • 工廠構(gòu)造函數(shù)

    • 說(shuō)明:
      1夷家、如果一個(gè)構(gòu)造函數(shù)并不總是返回一個(gè)新的對(duì)象蒸其,則可以將其定義為工廠構(gòu)造函數(shù)。
      2库快、工廠構(gòu)造函數(shù)摸袁,類似于設(shè)計(jì)模式中的工廠模式。
      3缺谴、在構(gòu)造方法前添加關(guān)鍵字factory 實(shí)現(xiàn)一個(gè)工廠構(gòu)造方法但惶。
      4、在工廠構(gòu)造方法中可以返回對(duì)象湿蛔。
    • 注意:工廠構(gòu)造函數(shù)無(wú)法訪問(wèn) this膀曾。
    • 示例:
      下面代碼演示工廠構(gòu)造函數(shù) 如何從緩存中返回對(duì)象。
      class Logger {
        final String name;
        bool mute = false;
      
        // _cache 是個(gè)庫(kù)私有變量阳啥,在變量名前加`_`即為私有成員變量
        static final Map<String, Logger> _cache =
            <String, Logger>{};
      
        //添加 factory 定義為工廠構(gòu)造函數(shù)
        factory Logger(String name) {
          //如果緩存中有name添谊,則取出返回,若不存在則添加并返回察迟。
          if (_cache.containsKey(name)) {
            return _cache[name];
          } else {
            final logger = new Logger._internal(name);
            _cache[name] = logger;
            return logger;
          }
        }
      
        Logger._internal(this.name);
      
        void log(String msg) {
          if (!mute) {
            print(msg);
          }
        }
      }
      
      調(diào)用:
      var logger = new Logger('UI');
      logger.log('Button clicked');
      
  • 重定向構(gòu)造函數(shù)

    • 說(shuō)明:
      1斩狱、有時(shí)候一個(gè)構(gòu)造函數(shù)會(huì)調(diào)動(dòng)類中的其他構(gòu)造函數(shù)耳高,則可以通過(guò)重定向構(gòu)造函數(shù)。
      2所踊、一個(gè)重定向構(gòu)造函數(shù)是沒(méi)有代碼的泌枪,在構(gòu)造函數(shù)聲明后,使用 : 調(diào)用其他構(gòu)造函數(shù)秕岛。
    • 示例:
      class Person {
      
          String name;
          int age;
      
          //語(yǔ)法糖寫(xiě)法
          Person(this.name, this.age);
      
          Person.formAge(int age): this("張三", age);
      
          //此種寫(xiě)法沒(méi)有給任何變量賦值碌燕,在調(diào)用后,name和age都為null
          Person.initParams(String name, int age);
      
          void printArgs() {
              print("name:$name继薛;age:$age");
          }
      
      }
      
  • 初始化列表

    • 說(shuō)明:
      1修壕、在構(gòu)造函數(shù)體執(zhí)行之前除了可以調(diào)用超類構(gòu)造函數(shù)之外,還可以初始化實(shí)例參數(shù)遏考。即初始化列表會(huì)在構(gòu)造方法體執(zhí)行前執(zhí)行慈鸠。
      2、使用: 設(shè)置初始化表達(dá)式灌具,使用 , 分隔初始化表達(dá)式青团。
      3、初始化列表常用于設(shè)置final 變量的值稽亏。
      官網(wǎng)警告: 初始化表達(dá)式等號(hào)右邊的部分不能訪問(wèn) this壶冒。(本人驗(yàn)證,似乎并非如此截歉。)
    • 示例:
      官網(wǎng)示例:
      class Point {
        num x;
        num y;
      
        Point(this.x, this.y);
      
        // Initializer list sets instance variables before
        // the constructor body runs.
        Point.fromJson(Map jsonMap)
            : x = jsonMap['x'],
              y = jsonMap['y'] {
          print('In Point.fromJson(): ($x, $y)');
        }
      }
      
      本地測(cè)試:
      /**
       * person
       */
      class Person {
          String name;
          int age;
          bool isMan;
      
          //初始化列表胖腾,加上了this
          Person(name, age):
                  this.name = name,
                  this.age = age;
      
          //初始化列表,加上了this
          Person.withMap(Map map): this.isMan = map["isMan"] {
              this.name = map["name"];
              this.age = map["age"];
          }
      
          void printArgs() {
              print("name:$name瘪松;age:$age");
          }
      
      }
      
      /**
       * main
       */
      import 'person.dart';
      void main() {
          Person p = new Person("張三", 33);
      
          //name:張三咸作;age:33;isMan:null
          p.printArgs();
      
          Person pp = Person.withMap({
              "name": "李四",
              "age": 23,
              "isMan": true});
          //name:李四宵睦;age:23记罚;isMan:true
          pp.printArgs();
      }
      
      注:本人在測(cè)試的時(shí)候,在初始化列表上的變量加上了this 關(guān)鍵字壳嚎,編譯并未報(bào)錯(cuò)桐智,也可以正常執(zhí)行輸出結(jié)果。
      這個(gè)地方不知是否是我的姿勢(shì)有誤烟馅,還是說(shuō)確實(shí)可以如此使用说庭,希望有知道的盆友可以解答我的困惑,非常感謝郑趁。
      不過(guò)刊驴,一切以官方為準(zhǔn),最好不要加上this
    • 設(shè)置final 變量:
      import 'dart:math';
      
      class Point {
        final num x;
        final num y;
        final num distanceFromOrigin;
      
        Point(x, y)
            : x = x,
              y = y,
              distanceFromOrigin = sqrt(x * x + y * y);
      }
      
      main() {
        var p = new Point(2, 3);
        print(p.distanceFromOrigin);
      }
      

3、成員(變量與函數(shù))

  • 說(shuō)明:
    1捆憎、對(duì)象的成員包括方法和數(shù)據(jù) (函數(shù) 和 實(shí)例變量)舅柜。
    2、當(dāng)你調(diào)用一個(gè)函數(shù)的時(shí)候躲惰,你是在一個(gè)對(duì)象上 調(diào)用:函數(shù)需要訪問(wèn)對(duì)象的方法 和數(shù)據(jù)致份。
    3、所有沒(méi)有初始化的變量值都是 null础拨。
    4知举、函數(shù)不能被重載,可以被子類覆寫(xiě)太伊。

  • 調(diào)用:

    • 使用點(diǎn). 來(lái)引用對(duì)象的變量或者方法。
    • 使用 ?. 來(lái)替代 . 可以避免當(dāng)左邊對(duì)象為 null 時(shí)候 拋出異常:
       class Person {
           //定義實(shí)例變量
           String name;
           int age;
    
           //定義實(shí)例函數(shù)         
           void printArgs() {
              print("name:${name}逛钻;age:${age}");
           }
    
            //演示方法不能被重載
           //編譯錯(cuò)誤:The name 'printArgs' is already defined.
           void printArgs(int age) {
              print("name:${name}僚焦;age:${age}");
           }
       }
       
       void main() {
           Person p = new Person();
           p.name = "張三";
           p.age = 33;
       
           //name:張三;age:33
           p.printArgs();
       
           Person pp;
           pp?.name = "李四";
           
           //報(bào)錯(cuò):Unhandled exception:
           //NoSuchMethodError: The setter 'age=' was called on null.
           //Receiver: null
           //Tried calling: age=23
           pp.age = 23;
       }
    
  • 實(shí)例變量

    • 說(shuō)明:
      1曙痘、所有沒(méi)有初始化的變量值都是 null芳悲。
      2剧浸、每個(gè)實(shí)例變量都會(huì)自動(dòng)生成一個(gè) getter 方法(隱含的)彼硫。
      3祠够、非final 變量會(huì)自動(dòng)生成一個(gè) setter 方法(隱含的)叽掘。
      4殿漠、如果你在實(shí)例變量定義的時(shí)候初始化該變量(不是 在構(gòu)造函數(shù)或者其他方法中初始化)雇庙,該值是在實(shí)例創(chuàng)建的時(shí)候 初始化的掖鱼,也就是在構(gòu)造函數(shù)和初始化參數(shù)列 表執(zhí)行之前帮寻。
    • 示例:
      class Point {
        num x;
        num y;
      }
      
      main() {
        var point = new Point();
        point.x = 4;          // 調(diào)用x旺订,是用了setter方法
        assert(point.x == 4); // 調(diào)用x弄企,是用了getter方法
        assert(point.y == null); // 變量默認(rèn)是null
      }
      
  • 實(shí)例函數(shù)

    • 說(shuō)明
      1、函數(shù)是類中定義的方法区拳,是類對(duì)象的行為拘领。
      2、對(duì)象的實(shí)例函數(shù)可以訪問(wèn) this樱调。
    • 示例
      import 'dart:math';
      
      class Point {
        num x;
        num y;
        Point(this.x, this.y);
      
        num distanceTo(Point other) {
          var dx = x - other.x;
          var dy = y - other.y;
          return sqrt(dx * dx + dy * dy);
        }
      }
      
  • 計(jì)算屬性-Getters And Setters

    • 說(shuō)明
      1约素、Getters 和 setters 是用來(lái)設(shè)置和訪問(wèn)對(duì)象屬性的特殊函數(shù)
      2笆凌、每個(gè)實(shí)例變量都隱含的具有一個(gè) getter圣猎, 如果變量不是 final 的則還有一個(gè) setter
      3菩颖、你可以通過(guò)實(shí)行 gettersetter 來(lái)創(chuàng)建新的屬性样漆, 使用 getset 關(guān)鍵字定義 gettersetter
      4晦闰、計(jì)算屬性的值是通過(guò)計(jì)算而來(lái)放祟,本身不存儲(chǔ)值鳍怨。
      5、計(jì)算屬性賦值跪妥,其實(shí)是通過(guò)計(jì)算轉(zhuǎn)換到其他實(shí)例變量鞋喇。
      6、在開(kāi)始使用實(shí)例變量眉撵,后來(lái)可以把實(shí)例變量用函數(shù)包裹起來(lái)侦香,而調(diào)用你代碼的地方不需要修改。

    • 官網(wǎng)注意(本人此處還未搞明白什么意思)
      1纽疟、像 (++) 這種操作符不管是否定義 getter 都會(huì)正確的執(zhí)行罐韩。 為了避免其他副作用, 操作符只調(diào)用 getter 一次污朽,然后把其值保存到一個(gè)臨時(shí)變量中散吵。

    • 示例

      class Rectangle {
        num left;
        num top;
        num width;
        num height;
      
        Rectangle(this.left, this.top, this.width, this.height);
      
        // 定義兩個(gè)計(jì)算屬性:right 和 bottom.
        num get right             => left + width;
            set right(num value)  => left = value - width;
        num get bottom            => top + height;
            set bottom(num value) => top = value - height;
      }
      
      main() {
        var rect = new Rectangle(3, 4, 20, 15);
        assert(rect.left == 3);
        rect.right = 12;
        assert(rect.left == -8);
      }
      
  • 類變量和類函數(shù)(靜態(tài)成員)

    • 說(shuō)明
      1、使用static 關(guān)鍵字來(lái)實(shí)現(xiàn)類級(jí)別的變量和函數(shù)
      2蟆肆、靜態(tài)成員不能訪問(wèn)非靜態(tài)成員(this調(diào)用)矾睦,非靜態(tài)成員可以訪問(wèn)靜態(tài)成員。
      [靜態(tài)函數(shù)不再類實(shí)例上執(zhí)行炎功, 所以無(wú)法訪問(wèn) this]枚冗。
      3、類中的常量需要使用static const 聲明蛇损。

      4赁温、靜態(tài)變量對(duì)于類級(jí)別的狀態(tài)是非常有用的。
      5州藕、靜態(tài)變量在第一次使用的時(shí)候才被初始化束世。
      6、靜態(tài)函數(shù)還可以當(dāng)做編譯時(shí)常量使用床玻。例如毁涉,你可以把靜態(tài)函數(shù)當(dāng)做常量構(gòu)造函數(shù)的參數(shù)來(lái)使用。
      注意:對(duì)于通用的或者經(jīng)常使用的靜態(tài)函數(shù)锈死,考慮使用頂級(jí)方法而不是靜態(tài)函數(shù)贫堰。

    • 示例

      class Page {
      
          int x;
          static int currentPage = 1;
      
          static void upPage() {
              currentPage++;
              print("up--> currentPage = $currentPage");
          }
      
          static void downPage() {
              //報(bào)錯(cuò):Invalid reference to 'this' expression.
              //print(this.x);    //不能訪問(wèn)非靜態(tài)成員
              currentPage--;
              print("down--> currentPage = $currentPage");
          }
      }
      
      void main() {
          //1
          print(Page.currentPage);
      
          //up--> currentPage = 2
          Page.upPage();
      
          //down--> currentPage = 1
          Page.downPage();
      }
      
  • 抽象函數(shù)
    詳見(jiàn)抽象類

  • 對(duì)象call方法(可調(diào)用的類)

    • 說(shuō)明:
      1、如果 Dart 類實(shí)現(xiàn)了 call() 函數(shù)待牵,則對(duì)象可以當(dāng)做方法來(lái)調(diào)用其屏。
      2、只要方法名為call缨该,無(wú)論有無(wú)參數(shù)偎行、有無(wú)返回值,都是可以的
    • 示例:
      class Person {
          String name;
          int age;
      
          void call() {
              print("name:$name;age:$age");
          }
      }
      class Student {
          String name;
          int age;
      
          void call(String name, int age) {
              print("name:$name蛤袒;age:$age");
          }
      
      }
      class Worker {
          String name;
          int age;
      
          String call(String name, int age) {
              return "name:$name熄云;age:$age";
          }
      
      }
      
      void main() {
          Person person = Person();
          //name:null;age:null
          person();  //因?yàn)閷?shí)現(xiàn)了call方法妙真,直接調(diào)用即可
      
          Student student = Student();
          //name:學(xué)生缴允;age:15
          student("學(xué)生", 15);
      
          Worker worker = new Worker();
          String info = worker("工人", 33);
          //work==>name:工人;age:33
          print("work==>$info");
      }
      

更多相關(guān)信息: Emulating Functions in Dart(在 Dart 中模擬方法)

4珍德、繼承與多態(tài)

  • 定義
    1练般、使用關(guān)鍵字extends 繼承一個(gè)類
    2、子類會(huì)繼承父類可見(jiàn)的屬性和方法(可以用@override 注解來(lái)表明為覆寫(xiě)方法)锈候,不會(huì)繼承構(gòu)造方法
    3薄料、子類能夠覆寫(xiě)父類的方法、gettersetter
    4泵琳、Dart具有單繼承都办、多態(tài)性
    5、Dart的多態(tài)性可以讓子類實(shí)例指向父類的變量虑稼。

    • 示例
      class Person {
          String name;
          int age;
      
          void work() {
              print("person--->working...");
          }
      
          bool get isAdult => age > 18;
      
          void printArgs() {
              print("person==>name:$name;age:$age势木;isAdult:$isAdult");
          }
      
      }
      
      class Student extends Person {
      
          Student() {
      
          }
      
          Student.initParams(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          void study() {
              print("student--->studying...");
          }
      
      
          @override
          bool get isAdult => age > 15;
      
          @override
          void printArgs() {
              //super.printArgs();
              print("student==>name:$name蛛倦;age:$age;isAdult:$isAdult");
        }
      }
      
      void main() {
          Student student = Student();
          student.name = "張三";
          student.age = 16;
      
          //person--->working...
          student.work();
          //student==>name:張三啦桌;age:16溯壶;isAdult:true
          student.printArgs();
      
          //多態(tài)調(diào)用
          Person p = Student.initParams("李四", 17);
          //student==>name:李四;age:17甫男;isAdult:true
          p.printArgs();
          if (p is Student) {
             //student--->studying...
             p.study();
          }
      }
      
  • 繼承中的構(gòu)造函數(shù)
    1且改、子類的構(gòu)造方法默認(rèn)會(huì)調(diào)用父類的無(wú)名無(wú)參構(gòu)造函數(shù)。
    2板驳、如果父類沒(méi)有無(wú)名無(wú)參的構(gòu)造函數(shù)又跛,則需要顯式調(diào)用父類構(gòu)造函數(shù)。
    3若治、在構(gòu)造方法參數(shù)后使用: 顯式調(diào)用父類構(gòu)造函數(shù)慨蓝。
    4、如果有初始化列表端幼,初始化列表要放在父類構(gòu)造函數(shù)之前礼烈。

    注:子類不能使用重定向構(gòu)造函數(shù)(無(wú)方法體的:設(shè)置變量的構(gòu)造函數(shù))進(jìn)行自定義函數(shù)。本人認(rèn)為:因?yàn)槌跏蓟瘏?shù)要提前于父類構(gòu)造函數(shù)婆跑,這個(gè)時(shí)候還不能使用this(待驗(yàn)證)此熬。

    • 示例
       class Person {
           String name;
           int age;
       
           /*
           #1
           Person() {
               print("person===");
           }
           */
       
           Person(this.name);
       
           Person.initParams(this.name, this.age);
       
       }
       
       class Student extends Person {
       
           //第一種
           Student(String name) : super(name);
       
           //第二種
           Student.initParams(String name, int age) : super.initParams(name, age);
                 
           // 無(wú)法創(chuàng)建
           // Student.initParams(String name, int age):this.name = name;
       }
       
       void main() {
           //#1
           //打印:person===
           //Student student = Student();
       }
    

    初始化列表:

      class Person {
          String name;
          int age;
      
          Person(this.name);
      
          Person.initParams(this.name, this.age);
      
      }
      
      class Student extends Person {
      
          final bool isMan;
          
          Student.withParams(String name, int age, bool man) :
                  isMan = man,
                  super.initParams(name, age);
      }
      ```
    
    
  • 構(gòu)造方法執(zhí)行順序
    1、父類的構(gòu)造函數(shù)在子類構(gòu)造函數(shù)的方法體開(kāi)始執(zhí)行的位置調(diào)用犀忱。
    2募谎、如果有初始化列表,初始化列表會(huì)在父類構(gòu)造函數(shù)之前執(zhí)行峡碉。

    • 示例:
      class Person {
          String name;
          int age;
          
          Person(this.name);
      
          Person.initParams(this.name, this.age) {
              print("Person.initParams====");
          }
      
      }
      
      class Student extends Person {
      
          final bool isMan;
      
          Student.withParams(String name, int age, bool man) :
                  isMan = getMan(man),
                  super.initParams(name, age) {
              print("Student.withParams====");
          }
      
          static bool getMan(man) {
              print("Student===man:$man");
              return man;
          }
      
      }
      
      void main() {
          Student student = Student.withParams("學(xué)生", 17, true);
          
          /**
           * 打印如下:
              Student===man:true
              Person.initParams====
              Student.withParams====
           */
      }
      
  • 擴(kuò)展:
    查看所有超類Object近哟,其中有一些成員的前面用關(guān)鍵字external 來(lái)修飾,它的作用是根據(jù)不同平臺(tái)(Dart是跨平臺(tái)的語(yǔ)言)語(yǔ)言而有不同的具體實(shí)現(xiàn)鲫寄。

      /**
       * Returns a string representation of this object.
       */
      external String toString();
    

5吉执、抽象類

  • 定義
    1、抽象類是一個(gè)不能被實(shí)例化的類地来。
    2戳玫、使用 abstract 修飾符定義一個(gè) 抽象類

  • 說(shuō)明:
    1未斑、抽象類通常用來(lái)定義接口咕宿, 以及部分實(shí)現(xiàn)。
    2蜡秽、如果你希望你的抽象類是可實(shí)例化的府阀,則定義一個(gè) 工廠構(gòu)造函數(shù)
    3芽突、抽象類通常具有 抽象函數(shù)试浙。
    4、抽象類不能直接被實(shí)例化寞蚌。
    5田巴、抽象類可以沒(méi)有抽象方法。
    6挟秤、有抽象方法的類一定要聲明為抽象類壹哺。

    • 示例

      abstract class Person {
        void run();
      
        void printArgs() {
          print("person===");
        }
      }
      
      class Student extends Person {
      
        @override
        void run() {
          print("student run...");
        }
      }
      
      void main() {
        Person p = new Student();
        //student run...
        p.run();
      }
      
    • 注意:
      官網(wǎng)說(shuō)明:下面的類(示例)不是抽象的,但是定義了一個(gè)抽象函數(shù)艘刚,這樣的類是可以被實(shí)例化的管宵。
      但經(jīng)過(guò)測(cè)試,確實(shí)是有警告攀甚,運(yùn)行也會(huì)報(bào)錯(cuò)啄糙,不太明白這里所說(shuō)的可以被實(shí)例化是什么意思。

       // This class is declared abstract and thus
       // can't be instantiated.
       abstract class AbstractContainer {
         // ...Define constructors, fields, methods...
       
         void updateChildren(); // Abstract method.
       }
       
       
       class SpecializedContainer extends AbstractContainer {
         // ...Define more constructors, fields, methods...
       
         void updateChildren() {
           // ...Implement updateChildren()...
         }
       
         // Abstract method causes a warning but
         // doesn't prevent instantiation.
         void doSomething();
       }
    
  • 抽象函數(shù)

    • 抽象方法不用abstract 修飾云稚,沒(méi)有方法體實(shí)現(xiàn)隧饼。
    • 實(shí)例函數(shù)、 getter静陈、和 setter 函數(shù)可以為抽象函數(shù)燕雁。
    • 抽象函數(shù)是只定義函數(shù)接口但是沒(méi)有實(shí)現(xiàn)的函數(shù)诞丽,由子類來(lái)實(shí)現(xiàn)該函數(shù)。如果用分號(hào)來(lái)替代函數(shù)體則這個(gè)函數(shù)就是抽象函數(shù)拐格。
    • 調(diào)用一個(gè)沒(méi)實(shí)現(xiàn)的抽象函數(shù)會(huì)導(dǎo)致運(yùn)行時(shí)異常僧免。

6、接口

  • 定義
    一個(gè)類通過(guò)使用關(guān)鍵字implements 來(lái)實(shí)現(xiàn)一個(gè)或者多個(gè)接口捏浊。
  • 說(shuō)明
    1懂衩、類和接口是統(tǒng)一的,類就是接口金踪。
    2浊洞、一個(gè)類實(shí)現(xiàn)了某個(gè)接口,就要實(shí)現(xiàn)此接口的每個(gè)成員胡岔。
    3法希、如果是復(fù)用已有類的接口,使用繼承(extends)靶瘸。
    4苫亦、如果只是使用已有類的外在行為,使用接口(implements)怨咪。
    5屋剑、每個(gè)類都隱式的定義了一個(gè)包含所有實(shí)例成員的接口
  • 示例:
       class Person {
           String name;
           int get age => 18;
       
           void run() {
               print("run...");
           }
       }
       
       class Student implements Person {
         @override
         String name;
       
         @override
         // TODO: implement age
         int get age => 15;
       
         @override
         void run() {
             print("student run...");
         }
       
       }
       
       void main() {
           Student student = Student();
           student.run();
       }
    
  • 建議:
    1、將抽象類作為接口使用诗眨,讓子類來(lái)實(shí)現(xiàn)(因?yàn)轭惣唇涌诒穑钥梢酝ㄟ^(guò)關(guān)鍵字implements來(lái)實(shí)現(xiàn))。
    示例:
       abstract class Person {
           void run();
       }
       
       class Student implements Person {
         String name;
       
         int get age => 15;
       
         @override
         void run() {
             print("student run...");
         }
       
       }
       
       void main() {
           Student student = Student();
           //student run...
           student.run();
       }
    

7辽话、枚舉類

  • 定義
    使用關(guān)鍵字enum 來(lái)定義一個(gè)枚舉類型。

  • 說(shuō)明
    1卫病、枚舉類型通常稱之為 enumerations 或者 enums油啤,是一種特殊的類,用來(lái)表現(xiàn)一個(gè)固定數(shù)目的常量蟀苛。
    2益咬、枚舉是一種有窮序列集的數(shù)據(jù)類型。
    3帜平、常用于代替常量幽告,控制語(yǔ)句等。

  • 特性
    1裆甩、枚舉中的index 屬性從0開(kāi)始冗锁,依次累加。
    2嗤栓、枚舉中的values 屬性可以列舉出所有的枚舉值冻河。x
    3箍邮、無(wú)法顯示的初始化一個(gè)枚舉類型,即不能指定原始值(給枚舉常量賦值)叨叙。
    4锭弊、無(wú)法繼承枚舉類型、無(wú)法使用 mixin擂错、無(wú)法實(shí)現(xiàn)一個(gè)枚舉類型味滞。

  • 示例:

       enum Color {
           red,
           green,
           blue,
       
           //報(bào)錯(cuò),不能指定原始值
           //white = "#FFFFFF",
       }
       
       void main() {
       
           var color = Color.red;
       
           switch(color) {
               case Color.red:
                   print("紅色");
                   break;
               case Color.blue:
                   print("藍(lán)色");
                   break;
               case Color.green:
                   print("綠色");
                   break;
           }
           //紅色
           
           //index==> 0
           print("index==> ${color.index}");
    
           List<Color> values = Color.values;
           //[Color.red, Color.green, Color.blue]
           print(values);
       }
    

8钮呀、Mixins

  • 定義
    使用 with 關(guān)鍵字后面為一個(gè)或者多個(gè) mixin 名字來(lái)使用 mixin剑鞍。

  • 說(shuō)明
    1、Mixins 類似于多繼承行楞,實(shí)在多類繼承中重用一個(gè)類代碼的方式攒暇。
    2、作為Mixin的類不能顯示聲明構(gòu)造函數(shù)子房,不能調(diào)用 super 形用。(由于沿著繼承鏈傳遞構(gòu)造函數(shù)參數(shù)的需要,該約束能避免出現(xiàn)新的連鎖問(wèn)題证杭。)
    3田度、作為Mixin的類只能繼承自Object

  • 參考鏈接:
    Dart學(xué)習(xí)筆記(33):Mixin混合模式

  • 示例

    • 繼承示例:

      class A {
          void a() {
              print("A.a...");
          }
      }
      
      class B {
      
          void a() {
              print("B.a...");
          }
          void b() {
              print("B.b...");
          }
      }
      
      class C {
      
          void a() {
              print("C.a...");
          }
          void b() {
              print("C.b...");
          }
      
          void c() {
              print("C.c...");
          }
      }
      
      class D extends A with B, C {
      
      }
      
      void main() {
          D d = D();
          //C.a...
          d.a();
      }
      

      說(shuō)明:
      這里打印了C.a... 是和繼承的順序有關(guān)的解愤,如果將D 類繼承BC 的順序互換镇饺,則會(huì)調(diào)用B 中的方法,打印結(jié)果為B.a...送讲。

    • 組合示例:

      abstract class Engine {
          void work();
      }
      
      class OilEngine implements Engine {
        @override
        void work() {
          print("Work with oil...");
        }
      
      }
      
      class ElectricEngine implements Engine {
      
        @override
        void work() {
          print("Work with electric...");
        }
      
      }
      
      class Tyre {
          String name;
      
          void run() {}
      
      }
      
      class Car = Tyre with ElectricEngine;
      
      class Bus = Tyre with OilEngine;
      

      說(shuō)明:
      這種方式一般可以實(shí)現(xiàn)模塊的組裝奸笤,將自己需要的模塊進(jìn)行組合,實(shí)現(xiàn)不同的功能哼鬓。

  • 官網(wǎng)說(shuō)明:
    從 Dart 1.13 開(kāi)始监右, 這兩個(gè)限制在 Dart VM 上 沒(méi)有那么嚴(yán)格了:

    • Mixins 可以繼承其他類,不再限制為繼承 Object异希。
    • Mixins 可以調(diào)用 super()健盒。

9、操作符

  • 對(duì)象操作符
    • ?.:條件成員訪問(wèn)
      as:類型轉(zhuǎn)換
      is:判斷是指定類型
      is!:判斷非指定類型
      ..:級(jí)聯(lián)操作称簿,即可連續(xù)調(diào)用對(duì)象成員扣癣,因?yàn)闀?huì)返回當(dāng)前對(duì)象。
    • 示例
      class Person {
          String name;
          int age;
      
          void work() {
            print("person--->name:$name憨降;age:$age");
          }
      
      }
      
      void main() {
          var p;
          p = "";
          p = new Person();
          //不會(huì)報(bào)錯(cuò)
          p?.age = 43;
      
          p.name = "張三";
          p.age = 43;
          //person--->name:張三父虑;age:43
          (p as Person).work();
      
          if (p is Person) {
              //person--->name:張三;age:43
              p.work();
          }
      
          Person person = Person();
          person..name = "Tom"
                ..age = 33
                ..work(); //person--->name:Tom授药;age:33
      }
      
  • 操作符覆寫(xiě)
    • 說(shuō)明:
      1频轿、操作符的覆寫(xiě)需要在類中定義垂涯。
      2、如果覆寫(xiě)了 == 航邢,則還應(yīng)該覆寫(xiě)對(duì)象的 hashCodegetter 函數(shù)耕赘。 關(guān)于 覆寫(xiě) ==hashCode 的示例請(qǐng)參考 實(shí)現(xiàn) map 的 keys
    • 可覆寫(xiě)操作符
      < + | []
      > / ^ []=
      <= ~/ & ~
      >= * << ==
      % >>
    • 格式:
      class Xxx {
          
          返回類型 operator 操作符(參數(shù)1, 參數(shù)2, 參數(shù)....) {
              方法體
              return 返回值;
          }
      }
      
    • 示例:
      class Person {
          int age;
      
          Person(this.age);
      
          bool operator >(Person p) {
              return this.age > p.age;
          }
      
          int operator [](String ageParam) {
              if("age"==ageParam) {
                  return this.age;
              } else {
                  return 0;
              }
          }
      
          /**
           * 以下兩個(gè)覆寫(xiě)方法膳殷,可以通過(guò)右鍵選擇'Generate...'
           * 然后點(diǎn)擊選擇'== and hashCode'直接生成
           */
          @override
          bool operator ==(Object other) =>
              identical(this, other) ||
                  other is Person &&
                      runtimeType == other.runtimeType &&
                      age == other.age;
      
          @override
          int get hashCode => age.hashCode;
      
      }
      
      void main() {
          Person p1 = Person(22);
          Person p2 = Person(33);
          //p1>p2? ==> false
          print("p1>p2? ==> ${p1>p2}");
      
          //p1.age==> 22
          print("p1.age==> ${p1["age"]}");
      }
      

七操骡、泛型

1、定義

  • 方式
    1赚窃、使用 <…> 來(lái)聲明泛型
    2册招、通常情況下,使用一個(gè)字母來(lái)代表類型參數(shù)勒极, 例如 E, T, S, K, 和 V 等是掰。
    3、List 是一個(gè) 泛型 (或者 參數(shù)化) 類型辱匿,定義為List<E>键痛。

  • 使用泛型的原因
    1、在 Dart 中類型是可選的匾七,可以通過(guò)泛型來(lái)限定類型絮短。
    2、使用泛型可以有效地減少重復(fù)的代碼昨忆。 泛型可以在多種類型之間定義同一個(gè)實(shí)現(xiàn)丁频,同時(shí)還可以繼續(xù)使用檢查模式和靜態(tài)分析工具提供的代碼分析功能。
    3邑贴、如果你需要更加安全的類型檢查席里,則可以使用 參數(shù)化定義。

2拢驾、用法

  • 類的泛型

    • 說(shuō)明:
      在調(diào)用構(gòu)造函數(shù)的時(shí)候奖磁, 在類名字后面使用尖括號(hào)(<...>)來(lái)指定 泛型類型。
    • 示例:
      class Cache<T> {
      
          T value;
      
          T get() {
              return value;
          }
      
          void put(T value) {
              this.value = value;
          }
      }
      
      void main() {
          Cache<String> cacheStr = Cache();
          cacheStr.put("張三");
          //張三
          print(cacheStr.get());
      
          Cache<int> cacheNum = Cache();
          cacheNum.put(333);
          //333
          print(cacheNum.get());
      }
      
  • 函數(shù)的泛型

    • 說(shuō)明:
      在函數(shù)上使用泛型独旷,可以在如下地方使用類型參數(shù)(具體見(jiàn)示例):
      1、函數(shù)的返回值類型 (T)寥裂。
      2嵌洼、參數(shù)的類型 (T value).
      3、局部變量的類型 (T temp).

    注意: 版本說(shuō)明: 在 Dart SDK 1.21. 開(kāi)始可以使用泛型函數(shù)封恰。

    • 示例:
      class Util {
      
          static T put<T>(T value) {
              T temp;
              if (value!=null) {
                  temp = value;
              }
              print("temp = $temp");
              return value;
          }
      }
      
      void main() {
          //張三
          String value = Util.put<String>("張三");
          //報(bào)錯(cuò)麻养,提示類型錯(cuò)誤
          Util.put<String>(1);
      }
      

3、限制泛型類型

  • 說(shuō)明
    當(dāng)需要對(duì)泛型的具體類型進(jìn)行限定的時(shí)候诺舔,可以使用extends 關(guān)鍵字來(lái)限定泛型參數(shù)的具體類型鳖昌。
  • 示例:
       // T must be SomeBaseClass or one of its descendants.
       class Foo<T extends SomeBaseClass> {...}
       
       class Extender extends SomeBaseClass {...}
       
       void main() {
         // It's OK to use SomeBaseClass or any of its subclasses inside <>.
         var someBaseClassFoo = new Foo<SomeBaseClass>();
         var extenderFoo = new Foo<Extender>();
       
         // It's also OK to use no <> at all.
         var foo = new Foo();
       
         // Specifying any non-SomeBaseClass type results in a warning and, in
         // checked mode, a runtime error.
         // var objectFoo = new Foo<Object>();
       }
    

八备畦、庫(kù)和可見(jiàn)性

1、簡(jiǎn)介

  • Dart中的可見(jiàn)性以library 為單位
  • 默認(rèn)情況下许昨,每一個(gè)Dart文件就是一個(gè)庫(kù)
  • 使用_ 表示庫(kù)的私有性懂盐。
  • 使用import 關(guān)鍵字導(dǎo)入庫(kù)

2、示例:

  • person.dart

    /**
     * peerson
     */
    class Person {
        String name;
        int age;
    
        Person(name, age):
                this.name = name,
                this.age = age;
    
        void printArgs() {
            print("name:$name糕档;age:$age");
        }
    }
    
  • main

    import 'person.dart';
    
    void main() {
        Person p = new Person("張三", 33);
    
        //name:張三莉恼;age:33
        p.printArgs();
    }
    
image.png

九、異常

1速那、簡(jiǎn)介

  • 代碼中可以出現(xiàn)異常和捕獲異常俐银。
  • 異常表示一些未知的錯(cuò)誤情況。
  • 如果異常沒(méi)有捕獲端仰,則異常會(huì)拋出捶惜,導(dǎo)致拋出異常的代碼終止執(zhí)行。
  • 和 Java 不同的是荔烧,所有的 Dart 異常是非檢查異常吱七。
  • 方法不一定聲明了他們所拋出的異常, 并且你不要求捕獲任何異常茴晋。

詳情請(qǐng)參考 Exceptions 部分陪捷。

2、類型

注意:Dart 代碼可以拋出任何非null 對(duì)象為異常诺擅,不僅僅是實(shí)現(xiàn)了 Exception 或者 Error 的對(duì)象市袖。

3、Throw(拋出異常)

  • 可以拋出任意對(duì)象:
       throw 'Out of llamas!';
    
  • 可以使用箭頭函數(shù)=>
    拋出異常是一個(gè)表達(dá)式烁涌,所以可以在 => 語(yǔ)句中使用苍碟,也可以在其他能使用表達(dá)式的地方拋出異常。
       distanceTo(Point other) => throw new UnimplementedError();
    

4撮执、Catch(捕獲異常)

  • 異常捕獲的關(guān)鍵字
    on :捕獲異常微峰,指定異常類型
    catch:捕獲異常,捕獲異常對(duì)象抒钱。
    rethrow:重新拋出異常

  • 說(shuō)明:
    1蜓肆、捕獲異常可以避免異常繼續(xù)傳遞(你重新拋出rethrow異常除外)谋币。捕獲異常給你一個(gè)處理該異常的機(jī)會(huì)仗扬。
    2、對(duì)于可以拋出多種類型異常的代碼蕾额,你可以指定多個(gè)捕獲語(yǔ)句早芭。每個(gè)語(yǔ)句分別對(duì)應(yīng)一個(gè)異常類型,如果捕獲語(yǔ)句沒(méi)有指定異常類型诅蝶,則該可以捕獲任何異常類型退个。
    3募壕、函數(shù) catch() 可以帶有一個(gè)或者兩個(gè)參數(shù),第一個(gè)參數(shù)為拋出的異常對(duì)象语盈,第二個(gè)為堆棧信息 (一個(gè) StackTrace 對(duì)象)舱馅。

  • 示例:

       var foo = '';
       
       void misbehave() {
           try {
               foo = "You can't change a final variable's value.";
               //此處演示異常
               String sub = foo.substring(100);
           } on Exception catch (e) {
               print('Exception details:\n $e');
           } catch (e, s) {
               print('misbehave() partially handled ${e.runtimeType}.');
               print('Stack trace:\n$s');
               rethrow; // Allow callers to see the exception.
           }
       }
       
       void main() {
           try {
               misbehave();
           } catch (e) {
               print('main() finished handling ${e.runtimeType}.');
           }
       }
    
       /**
        *
        打印結(jié)果:
           misbehave() partially handled RangeError.
           Stack trace:
           #0      _StringBase.substring (dart:core/runtime/libstring_patch.dart:384:7)
           #1      misbehave (file:///Users/yu/Work/Workplace/Flutter/Dart/lesson2/exception_test.dart:7:26)
           #2      main (file:///Users/yu/Work/Workplace/Flutter/Dart/lesson2/exception_test.dart:19:9)
           #3      _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:300:19)
           #4      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
       
           main() finished handling RangeError.
        */
    

5、Finally

  • 要確保某些代碼執(zhí)行黎烈,不管有沒(méi)有出現(xiàn)異常都需要執(zhí)行习柠,可以使用 一個(gè) finally 語(yǔ)句來(lái)實(shí)現(xiàn)。

  • 如果沒(méi)有 catch 語(yǔ)句來(lái)捕獲異常照棋,則在執(zhí)行完 finally 語(yǔ)句后资溃,異常被拋出了。

  • 定義的 finally 語(yǔ)句在任何匹配的 catch 語(yǔ)句之后執(zhí)行烈炭。

  • 示例:

        try {
            String sub = "123".substring(10);
        } catch(e) {
            print('Exception details:\n$e');
        } finally {
            print("result........");
        }
    
    

十溶锭、元數(shù)據(jù)

1、簡(jiǎn)介:

  • 使用元數(shù)據(jù)可以給你的代碼添加其他額外信息符隙。
  • 元數(shù)據(jù)可以在 library趴捅、 classtypedef霹疫、 type parameter拱绑、 constructorfactory丽蝎、 function猎拨、 fieldparameter屠阻、或者 variable 聲明之前使用红省,也可以在 import 或者 export 指令之前使用。
  • 使用反射可以在運(yùn)行時(shí)獲取元數(shù)據(jù) 信息国觉。

2吧恃、定義:

  • 元數(shù)據(jù)注解是以 @ 字符開(kāi)頭,后面是一個(gè)編譯時(shí)常量(例如 deprecated)麻诀。
  • 調(diào)用一個(gè)常量構(gòu)造函數(shù)痕寓。

形如:@deprecated@override

3蝇闭、類型:

  • Dart內(nèi)置元數(shù)據(jù)注解:
    @deprecated
    @override
    @proxy

       class Television {
         /// _Deprecated: Use [turnOn] instead._
         @deprecated
         void activate() {
           turnOn();
         }
       
         /// Turns the TV's power on.
         void turnOn() {
           print('on!');
         }
       }
    
  • 自定義元數(shù)據(jù)注解:

       library todo;
       
       class todo {
         final String who;
         final String what;
       
         const todo(this.who, this.what);
       }
    

    使用 @todo 注解的示例:

       import 'todo.dart';
       
       @todo('seth', 'make this do something')
       void doSomething() {
         print('do something');
       }
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呻率,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子丁眼,更是在濱河造成了極大的恐慌筷凤,老刑警劉巖昭殉,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苞七,死亡現(xiàn)場(chǎng)離奇詭異藐守,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蹂风,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)卢厂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人惠啄,你說(shuō)我怎么就攤上這事慎恒。” “怎么了撵渡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵融柬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我趋距,道長(zhǎng)粒氧,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任节腐,我火速辦了婚禮外盯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翼雀。我一直安慰自己饱苟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布狼渊。 她就那樣靜靜地躺著箱熬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪囤锉。 梳的紋絲不亂的頭發(fā)上坦弟,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音官地,去河邊找鬼酿傍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛驱入,可吹牛的內(nèi)容都是我干的赤炒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼亏较,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼莺褒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起雪情,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤遵岩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體尘执,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舍哄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了誊锭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片表悬。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丧靡,靈堂內(nèi)的尸體忽然破棺而出蟆沫,到底是詐尸還是另有隱情,我是刑警寧澤温治,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布饭庞,位于F島的核電站,受9級(jí)特大地震影響熬荆,放射性物質(zhì)發(fā)生泄漏但绕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一惶看、第九天 我趴在偏房一處隱蔽的房頂上張望捏顺。 院中可真熱鬧,春花似錦纬黎、人聲如沸幅骄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拆座。三九已至,卻和暖如春冠息,著一層夾襖步出監(jiān)牢的瞬間挪凑,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工逛艰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留躏碳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓散怖,卻偏偏與公主長(zhǎng)得像菇绵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子镇眷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容