Dart語法學習

目錄

  • 參考資料
  • 語言特性
  • 關鍵字
  • 變量與常量
  • 數(shù)據(jù)類型
  • 運算符 operators
  • 控制流程語句
  • 異常 Exceptions
  • 函數(shù) Function
  • 類 Class
  • 類-方法
  • 類-抽象類
  • 類-隱式接口
  • 類-擴展一個類(重寫)
  • 庫和可見性
  • 異步支持

參考資料

語言特性

  • Dart所有的東西都是對象, 即使是數(shù)字numbers、函數(shù)function、null也都是對象,所有的對象都繼承自Object類。

  • Dart動態(tài)類型語言, 盡量給變量定義一個類型,會更安全,沒有顯示定義類型的變量在 debug 模式下類型會是 dynamic(動態(tài)的)。

  • Dart 在 running 之前解析你的所有代碼,指定數(shù)據(jù)類型和編譯時的常量,可以提高運行速度。

  • Dart中的類和接口是統(tǒng)一的,類即接口,你可以繼承一個類,也可以實現(xiàn)一個類(接口),自然也包含了良好的面向對象和并發(fā)編程的支持。

  • Dart 提供了頂級函數(shù)(如:main())。

  • Dart 沒有 public、private、protected 這些關鍵字,變量名以"_"開頭意味著對它的 lib 是私有的。

  • 沒有初始化的變量都會被賦予默認值 null。

  • final的值只能被設定一次。const 是一個編譯時的常量,可以通過 const 來創(chuàng)建常量值,var c=const[];,這里 c 還是一個變量,只是被賦值了一個常量值,它還是可以賦其它值。實例變量可以是 final,但不能是 const。

  • 編程語言并不是孤立存在的,Dart也是這樣,他由語言規(guī)范、虛擬機、類庫和工具等組成:

    • SDK:SDK 包含 Dart VM、dart2js、Pub、庫和工具。
    • Dartium:內嵌 Dart VM 的 Chromium ,可以在瀏覽器中直接執(zhí)行 dart 代碼。
    • Dart2js:將 Dart 代碼編譯為 JavaScript 的工具。
    • Dart Editor:基于 Eclipse 的全功能 IDE,并包含以上所有工具。支持代碼補全、代碼導航、快速修正、重構、調試等功能。

關鍵字(56個)

關鍵字 - - -
abstract do import super
as dynamic in switch
assert else interface sync*
enum implements is this
async* export library throw
await external mixin true
break extends new try
case factory null typedef
catch false operator var
class final part void
const finally rethrow while
continue for return with
covariant get set yield*
default if static deferred

變量與常量

  1. 變量聲明與初始化
  • 調用的變量name包含對String值為“張三” 的對象的引用,name推斷變量的類型是String,但可以通過指定它來更改該類型,如果對象不限于單一類型(沒有明確的類型),請使用Object或dynamic關鍵字。
  // 沒有明確類型,編譯的時候根據(jù)值明確類型
  var name = ‘Bob’; 
  Object name = '張三';
  dynamic name = '李四';

  // 顯示聲明將被推斷類型, 可以使用String顯示聲明字符串類型
  String name = 'Bob' ;
  
  1. 默認值
  • 未初始化的變量的初始值為null(包括數(shù)字),因此數(shù)字、字符串都可以調用各種方法
  //測試 數(shù)字類型的初始值是什么?
  int lineCount;
  // 為false的時候拋出異常
  assert(lineCount == null);
  print(lineCount); //打印結果為null,證明數(shù)字類型初始化值是null
  
  1. final and const

    • 如果您從未打算更改一個變量,那么使用 final 或 const,不是var,也不是一個類型。
      一個 final 變量只能被初始化一次; const變量是一個編譯時常量,(Const變量是隱式的final)
      final的頂級或類變量在第一次使用時被初始化。

    • 被final修飾的頂級變量或類變量在第一次聲明的時候就需要初始化。

    // The final variable 'outSideFinalName' must be initialized.
    final String outSideFinalName
    
    
    • 被final或者const修飾的變量,變量類型可以省略,建議指定數(shù)據(jù)類型。
     //可以省略String這個類型聲明
     final name = "Bob";
     final String name1  = "張三";
     
     const name2 = "alex";
     const String name3 = "李四";
    
    
    • 被 final 或 const 修飾的變量無法再去修改其值。
     final String outSideFinalName = "Alex";
     // outSideFinalName', a final variable, can only be set once
     // 一個final變量,只能被設置一次。
     outSideFinalName = "Bill";
     
     const String outSideName = 'Bill';
     // 這樣寫,編譯器提示:Constant variables can't be assigned a value
     // const常量不能賦值
     // outSideName = "小白";
    
    
    • flnal 或者 const 不能和 var 同時使用
     // Members can't be declared to be both 'const' and 'var'
     const var String outSideName = 'Bill';
     
     // Members can't be declared to be both 'final' and 'var'
     final var String name = 'Lili';
    
    
    • 常量如果是類級別的,請使用 static const
     // 常量如果是類級別的,請使用 static const
     static const String name3 = 'Tom';
     
     // 這樣寫保存
     // Only static fields can be declared as const
     // 只有靜態(tài)字段可以聲明為const
     //const String name3 = 'Tom';
    
    
    • 常量的運算
     const speed = 100; //速度(km/h)
     const double distance = 2.5 * speed; // 距離 = 時間 * 速度
    
     final speed2 = 100; //速度(km/h)
     final double distance2 = 2.5 * speed2; // 距離 = 時間 * 速度
     
    
    • const關鍵字不只是聲明常數(shù)變量,您也可以使用它來創(chuàng)建常量值,以及聲明創(chuàng)建常量值的構造函數(shù),任何變量都可以有一個常量值。
     // 注意: [] 創(chuàng)建的是一個空的list集合
     // const []創(chuàng)建一個空的、不可變的列表(EIL)。
     var varList = const []; // varList 當前是一個EIL
     final finalList = const []; // finalList一直是EIL
     const constList = const []; // constList 是一個編譯時常量的EIL
    
     // 可以更改非final,非const變量的值
     // 即使它曾經具有const值
     varList = ["haha"];
    
     // 不能更改final變量或const變量的值
     // 這樣寫,編譯器提示:a final variable, can only be set once
     // finalList = ["haha"];
     // 這樣寫,編譯器提示:Constant variables can't be assigned a value  
     // constList = ["haha"];
    
    
    • 在常量表達式中,該運算符的操作數(shù)必須為'bool'、'num'、'String'或'null', const常量必須用conat類型的值初始化。
    
    const String outSideName = 'Bill';
    final String outSideFinalName = 'Alex';
    const String outSideName2 = 'Tom';
    
    const aConstList = const ['1', '2', '3'];
    
    // In constant expressions, operands of this operator must be of type 'bool', 'num', 'String' or 'null'
    // 在常量表達式中,該運算符的操作數(shù)必須為'bool'、'num'、'String'或'null'。
    const validConstString = '$outSideName $outSideName2 $aConstList';
    
    // Const variables must be initialized with a constant value
    // const常量必須用conat類型的值初始化
    const validConstString = '$outSideName $outSideName2 $outSideFinalName';
    
    var outSideVarName='Cathy';
    // Const variables must be initialized with a constant value.
    // const常量必須用conat類型的值初始化
    const validConstString = '$outSideName $outSideName2 $outSideVarName';
    
    // 正確寫法
    const String outSideConstName = 'Joy';
    const validConstString = '$outSideName $outSideName2 $outSideConstName';
    
    

數(shù)據(jù)類型

  1. num

    • num 是數(shù)字類型的父類,有兩個子類 int 和 double。

    • int 根據(jù)平臺的不同,整數(shù)值不大于64位。在Dart VM上,值可以從-263到263 - 1,編譯成JavaScript的Dart使用JavaScript代碼,允許值從-253到253 - 1。

    • double 64位(雙精度)浮點數(shù),如IEEE 754標準所規(guī)定。

     int a = 1;
     print(a);
     
     double b = 1.12;
     print(b);
     
     // String -> int
     int one = int.parse('1');
     // 輸出3
     print(one + 2);
     
     // String -> double
     var onePointOne = double.parse('1.1');
     // 輸出3.1
     print(onePointOne + 2);
    
     // int -> String
     String oneAsString = 1.toString();
     // The argument type 'int' can't be assigned to the parameter type 'String'
     //print(oneAsString + 2);
     // 輸出 1 + 2
     print('$oneAsString + 2');
     // 輸出 1 2
     print('$oneAsString 2');
    
     // double -> String 注意括號中要有小數(shù)點位數(shù),否則報錯
     String piAsString = 3.14159.toStringAsFixed(2);
     // 截取兩位小數(shù), 輸出3.14
     print(piAsString);
     
     String aString = 1.12618.toStringAsFixed(2);
     // 檢查是否四舍五入,輸出1.13,發(fā)現(xiàn)會做四舍五入
     print(aString);
    
    
  2. String

    • Dart里面的String是一系列 UTF-16 代碼單元。
    • 您可以使用單引號或雙引號來創(chuàng)建一個字符串。
    • 單引號或者雙引號里面嵌套使用引號。
    • 或{} 來計算字符串中變量的值,需要注意的是如果是表達式需要${表達式}
     String singleString = 'abcdddd';
     String doubleString = "abcsdfafd";
     
     String sdString = '$singleString a "bcsd" ${singleString}';
     String dsString = "abc 'aaa' $sdString";
     print(sdString);
     print(dsString);
    
    
     String singleString = 'aaa';
     String doubleString = "bbb";
     // 單引號嵌套雙引號
     String sdString = '$singleString a "bbb" ${doubleString}';
     // 輸出 aaa a "bbb" bbb
     print(sdString);
     
     // 雙引號嵌套單引號
     String dsString = "${singleString.toUpperCase()} abc 'aaa' $doubleString.toUpperCase()";
     // 輸出 AAA abc 'aaa' bbb.toUpperCase(), 
     可以看出 ”$doubleString.toUpperCase()“ 沒有加“{}“,導致輸出結果是”bbb.toUpperCase()“
     print(dsString);
     
    
  3. bool

  • Dart 是強 bool 類型檢查,只有bool 類型的值是true 才被認為是true。
  • 只有兩個對象具有bool類型:true和false,它們都是編譯時常量。
  • Dart的類型安全意味著您不能使用 if(nonbooleanValue)assert(nonbooleanValue) 等代碼, 相反Dart使用的是顯式的檢查值。
  • assert 是語言內置的斷言函數(shù),僅在檢查模式下有效
    在開發(fā)過程中, 除非條件為真,否則會引發(fā)異常。(斷言失敗則程序立刻終止)。
  // 檢查是否為空字符串
  var fullName = '';
  assert(fullName.isEmpty);

  // 檢查0
  var hitPoints = 0;
  assert(hitPoints <= 0);

  // 檢查是否為null
  var unicorn;
  assert(unicorn == null);

  // 檢查是否為NaN
  var iMeantToDoThis = 0 / 0;
  assert(iMeantToDoThis.isNaN);

  1. List集合
  • 在Dart中,數(shù)組是List對象,因此大多數(shù)人只是將它們稱為List。
    Dart list文字看起來像JavaScript數(shù)組文字
 //創(chuàng)建一個int類型的list
 List list = [10, 7, 23];
 // 輸出[10, 7, 23]
 print(list);
 
 // 使用List的構造函數(shù),也可以添加int參數(shù),表示List固定長度,不能進行添加 刪除操作
 var fruits = new List();
 
 // 添加元素
 fruits.add('apples');
 
 // 添加多個元素
 fruits.addAll(['oranges', 'bananas']);
 
 List subFruits = ['apples', 'oranges', 'banans'];
 // 添加多個元素
 fruits.addAll(subFruits);
 
 // 輸出: [apples, oranges, bananas, apples, oranges, banans]
 print(fruits);
 
 // 獲取List的長度
 print(fruits.length);
 
 // 獲取第一個元素
 print(fruits.first);
 
 // 獲取元素最后一個元素
 print(fruits.last);
 
 // 利用索引獲取元素
 print(fruits[0]);
 
 // 查找某個元素的索引號
 print(fruits.indexOf('apples'));
 
 // 刪除指定位置的元素,返回刪除的元素
 print(fruits.removeAt(0));

 // 刪除指定元素,成功返回true,失敗返回false
 // 如果集合里面有多個“apples”, 只會刪除集合中第一個改元素
 fruits.remove('apples');

 // 刪除最后一個元素,返回刪除的元素
 fruits.removeLast();

 // 刪除指定范圍(索引)元素,含頭不含尾
 fruits.removeRange(start,end);

 // 刪除指定條件的元素(這里是元素長度大于6)
 fruits.removeWhere((item) => item.length >6);

 // 刪除所有的元素
 fruits.clear();

  • 注意事項:

    1. 可以直接打印list包括list的元素,list也是一個對象。但是java必須遍歷才能打印list,直接打印是地址值。

    2. 和java一樣list里面的元素必須保持類型一致,不一致就會報錯。

    3. 和java一樣list的角標從0開始。

    4. 如果集合里面有多個相同的元素“X”, 只會刪除集合中第一個改元素

  1. Map集合
  • 一般來說,map是將鍵和值相關聯(lián)的對象。鍵和值都可以是任何類型的對象。
    每個鍵只出現(xiàn)一次,但您可以多次使用相同的值。Dart支持map由map文字和map類型提供。

  • 初始化Map方式一: 直接聲明,用{}表示,里面寫key和value,每組鍵值對中間用逗號隔開。

 // Two keys in a map literal can't be equal.
 // Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '騰訊', 'baidu': '百度', 'Alibaba': '釘釘', 'Tenect': 'qq-music'};
 
 Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '騰訊', 'baidu': '百度'};
 // 輸出:{Alibaba: 阿里巴巴, Tencent: 騰訊, baidu: 百度}
 print(companys);

  • 創(chuàng)建Map方式二:先聲明,再去賦值。
 Map schoolsMap = new Map();
 schoolsMap['first'] = '清華';
 schoolsMap['second'] = '北大';
 schoolsMap['third'] = '復旦';
 // 打印結果 {first: 清華, second: 北大, third: 復旦}
 print(schoolsMap);

 var fruits = new Map();
 fruits["first"] = "apple";
 fruits["second"] = "banana";
 fruits["fifth"] = "orange";
 //換成雙引號,換成var 打印結果 {first: apple, second: banana, fifth: orange}
 print(fruits);
    
  • Map API
// 指定鍵值對的參數(shù)類型
var aMap = new Map<int, String>();

// Map的賦值,中括號中是Key,這里可不是數(shù)組
aMap[1] = '小米';

//Map中的鍵值對是唯一的
//同Set不同,第二次輸入的Key如果存在,Value會覆蓋之前的數(shù)據(jù)
aMap[1] = 'alibaba';

// map里面的value可以相同
aMap[2] = 'alibaba';

// map里面value可以為空字符串
aMap[3] = '';

// map里面的value可以為null
aMap[4] = null;

print(aMap);

// 檢索Map是否含有某Key
assert(aMap.containsKey(1));

//刪除某個鍵值對
aMap.remove(1); 

print(aMap);  

  • 注意事項

    1. map的key類型不一致也不會報錯。

    2. 添加元素的時候,會按照你添加元素的順序逐個加入到map里面,哪怕你的key,比如分別是 1,2,4,看起來有間隔,事實上添加到map的時候是{1:value,2:value,4:value} 這種形式。

    3. map里面的key不能相同。但是value可以相同,value可以為空字符串或者為null。

運算符

描述 操作符
一元后置操作符 expr++ expr-- () [] . ?.
一元前置操作符 expr !expr ~expr ++expr --expr
乘除 * / % ~/
加減 + -
位移 << >>
按位與 &
按位或
按位異或 ^
邏輯與 &&
邏輯或
關系和類型判斷 >= > <= < as is is!
== !=
如果為空 ??
條件表達式 expr1 ? expr2 : expr3
賦值 = *= /= ~/= %= += -= <<= >>= &= ^= = ??=
級聯(lián) ..

流程控制語句(Control flow statements)

  • if...else
  • for
  • while do-whild
  • break continue
  • switch...case
  • assert(僅在checked模式有效)

異常(Exceptions)

  1. throw
  • 拋出固定類型的異常
  throw new FormatException('Expected at least 1 section');

  • 拋出任意類型的異常

     throw 'Out of llamas!';
    
    
  • 因為拋出異常屬于表達式,可以將throw語句放在=>語句中,或者其它可以出現(xiàn)表達式的地方

     distanceTo(Point other) =>
         throw new UnimplementedError();
    
    
  1. catch
  • 將可能出現(xiàn)異常的代碼放置到try語句中,可以通過 on語句來指定需要捕獲的異常類型,使用catch來處理異常。
 try {
    breedMoreLlamas();
 } on OutOfLlamasException {
    // A specific exception
    buyMoreLlamas();
 } on Exception catch (e) {
    // Anything else that is an exception
    print('Unknown exception: $e');
 } catch (e, s) {
    print('Exception details:\n $e');
    print('Stack trace:\n $s');
 }

  1. rethrow
  • rethrow語句用來處理一個異常,同時希望這個異常能夠被其它調用的部分使用。

 final foo = '';

 void misbehave() {
    try {
      foo = "1";
    } catch (e) {
      print('2');
      rethrow;// 如果不重新拋出異常,main函數(shù)中的catch語句執(zhí)行不到
    }
 }

 void main() {
    try {
      misbehave();
    } catch (e) {
      print('3');
    }
 }

  1. finally

    • Dart的finally用來執(zhí)行那些無論異常是否發(fā)生都執(zhí)行的操作。
      final foo = '';
    
      void misbehave() {
        try {
          foo = "1";
        } catch (e) {
          print('2');
        }
      }
    
      void main() {
        try {
          misbehave();
        } catch (e) {
          print('3');
        } finally {
          print('4'); // 即使沒有rethrow最終都會執(zhí)行到
        }
      }
    
    

函數(shù) Function

  • 以下是一個實現(xiàn)函數(shù)的例子:
  bool isNoble(int atomicNumber) {
     return _nobleGases[atomicNumber] != null;
  }     

  1. main()函數(shù)

    • 每個應用程序都必須有一個頂層main()函數(shù),它可以作為應用程序的入口點。該main()函數(shù)返回void并具有List<String>參數(shù)的可選參數(shù)。
    void main() {
       querySelector('#sample_text_id')
           ..text = 'Click me!'
           ..onClick.listen(reverseText);
    }
    
    
    • 級聯(lián)符號..允許您在同一個對象上進行一系列操作。除了函數(shù)調用之外,還可以訪問同一對象上的字段。這通常會為您節(jié)省創(chuàng)建臨時變量的步驟,并允許您編寫更流暢的代碼。
    querySelector('#confirm') // Get an object.
        ..text = 'Confirm' // Use its members.
        ..classes.add('important')
        ..onClick.listen((e) => window.alert('Confirmed!'));
    
    
    • 上述例子相對于:
     var button = querySelector('#confirm');
     button.text = 'Confirm';
     button.classes.add('important');
     button.onClick.listen((e) => window.alert('Confirmed!'));
    
    
    • 級聯(lián)符號也可以嵌套使用。 例如:
      final addressBook = (AddressBookBuilder()
       ..name = 'jenny'
       ..email = 'jenny@example.com'
       ..phone = (PhoneNumberBuilder()
             ..number = '415-555-0100'
             ..label = 'home')
           .build())
       .build();
       
    
    • 當返回值是void時不能構建級聯(lián)。 例如,以下代碼失敗:
    var sb = StringBuffer();
    sb.write('foo') // 返回void
      ..write('bar'); // 這里會報錯
    
    
    • 注意: 嚴格地說,級聯(lián)的..符號不是操作符。它只是Dart語法的一部分。
  1. 可選參數(shù)

    • 可選的命名參數(shù), 定義函數(shù)時,使用{param1, param2, …},用于指定命名參數(shù)。例如:
     //設置[bold]和[hidden]標志
     void enableFlags({bool bold, bool hidden}) {
          // ... 
     }  
     
     enableFlags(bold: true, hidden: false);
    
    
    • 可選的位置參數(shù),用[]它們標記為可選的位置參數(shù):
      String say(String from, String msg, [String device]) {
          var result = '$from says $msg';
          if (device != null) {
             result = '$result with a $device';
          }
          return result;
      }
    
    
    • 下面是一個不帶可選參數(shù)調用這個函數(shù)的例子:
      say('Bob', 'Howdy'); //結果是: Bob says Howdy
    
    
    • 下面是用第三個參數(shù)調用這個函數(shù)的例子:
      say('Bob', 'Howdy', 'smoke signal'); //結果是:Bob says Howdy with a smoke signal
    
    
  2. 默認參數(shù)

    • 函數(shù)可以使用=為命名參數(shù)和位置參數(shù)定義默認值。默認值必須是編譯時常量。如果沒有提供默認值,則默認值為null。

    • 下面是為命名參數(shù)設置默認值的示例:

      // 設置 bold 和 hidden 標記的默認值都為false
      void enableFlags2({bool bold = false, bool hidden = false}) {
           // ...
      }
    
      // 調用的時候:bold will be true; hidden will be false.
      enableFlags2(bold: true);
    
    
    • 下一個示例顯示如何為位置參數(shù)設置默認值:
     String say(String from, String msg,
        [String device = 'carrier pigeon', String mood]) {
            var result = '$from says $msg';
            if (device != null) {
                result = '$result with a $device';
            }
            if (mood != null) {
                result = '$result (in a $mood mood)';
            }
            return result;
     }
    
     //調用方式:
     say('Bob', 'Howdy'); //結果為:Bob says Howdy with a carrier pigeon;
    
    
    • 您還可以將list或map作為默認值傳遞。下面的示例定義一個函數(shù)doStuff(),該函數(shù)指定列表參數(shù)的默認list和gifts參數(shù)的默認map。
     // 使用list 或者map設置默認值
     void doStuff(
         {List<int> list = const [1, 2, 3],
         Map<String, String> gifts = const {'first': 'paper', 
         'second': 'cotton', 'third': 'leather'
        }}) {
         print('list:  $list');
         print('gifts: $gifts');
     }
    
    
  3. 作為一個類對象的功能

  • 您可以將一個函數(shù)作為參數(shù)傳遞給另一個函數(shù)。

  void printElement(int element) {
     print(element);
  }

  var list = [1, 2, 3];

  // 把 printElement函數(shù)作為一個參數(shù)傳遞進來
  list.forEach(printElement);

  • 您也可以將一個函數(shù)分配給一個變量。

  var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
  assert(loudify('hello') == '!!! HELLO !!!');

  1. 匿名函數(shù)

    • 大多數(shù)函數(shù)都能被命名為匿名函數(shù),如 main() 或 printElement()。您還可以創(chuàng)建一個名為匿名函數(shù)的無名函數(shù),有時也可以創(chuàng)建lambda或閉包。您可以為變量分配一個匿名函數(shù),例如,您可以從集合中添加或刪除它。

    • 一個匿名函數(shù)看起來類似于一個命名函數(shù) - 0或更多的參數(shù),在括號之間用逗號和可選類型標注分隔。

    • 下面的代碼塊包含函數(shù)的主體:

    
      ([[Type] param1[, …]]) { 
         codeBlock; 
      }; 
    
    
    • 下面的示例定義了一個具有無類型參數(shù)的匿名函數(shù)item,該函數(shù)被list中的每個item調用,輸出一個字符串,該字符串包含指定索引處的值。
    
     var list = ['apples', 'bananas', 'oranges'];
     list.forEach((item) {
        print('${list.indexOf(item)}: $item');
     });
    
    
    • 如果函數(shù)只包含一條語句,可以使用箭頭符號=>來縮短它, 比如上面的例2可以簡寫成:
    
     list.forEach((item) => print('${list.indexOf(item)}: $item'));
    
    
  2. 返回值

  • 所有函數(shù)都返回一個值,如果沒有指定返回值,則語句return null,隱式地附加到函數(shù)體。

  foo() {}
  assert(foo() == null);
  

類(Classes)

  1. 對象
  • Dart 是一種面向對象的語言,并且支持基于mixin的繼承方式。
  • Dart 語言中所有的對象都是某一個類的實例,所有的類有同一個基類--Object。
  • 基于mixin的繼承方式具體是指:一個類可以繼承自多個父類。
  • 使用new語句來構造一個類,構造函數(shù)的名字可能是ClassName,也可以是ClassName.identifier, 例如:

  var jsonData = JSON.decode('{"x":1, "y":2}');

  // Create a Point using Point().
  var p1 = new Point(2, 2);

  // Create a Point using Point.fromJson().
  var p2 = new Point.fromJson(jsonData);


  • 使用.(dot)來調用實例的變量或者方法。

  var p = new Point(2, 2);

  // Set the value of the instance variable y.
  p.y = 3;

  // Get the value of y.
  assert(p.y == 3);

  // Invoke distanceTo() on p.
  num distance = p.distanceTo(new Point(4, 4));

  • 使用?.來確認前操作數(shù)不為空, 常用來替代. , 避免左邊操作數(shù)為null引發(fā)異常。
```

 // If p is non-null, set its y value to 4.
 p?.y = 4;

```
  • 使用const替代new來創(chuàng)建編譯時的常量構造函數(shù)。
```

 var p = const ImmutablePoint(2, 2);

``` 
  • 使用runtimeType方法,在運行中獲取對象的類型。該方法將返回Type 類型的變量。
```

 print('The type of a is ${a.runtimeType}');

```
  1. 實例化變量(Instance variables)
  • 在類定義中,所有沒有初始化的變量都會被初始化為null。

 class Point {
    num x; // Declare instance variable x, initially null.
    num y; // Declare y, initially null.
    num z = 0; // Declare z, initially 0.
 }

  • 類定義中所有的變量, Dart語言都會隱式的定義 setter 方法,針對非空的變量會額外增加 getter 方法。
 class Point {
    num x;
    num y;
 }

 main() {
    var point = new Point();
    point.x = 4;          // Use the setter method for x.
    assert(point.x == 4); // Use the getter method for x.
    assert(point.y == null); // Values default to null.
 }

  1. 構造函數(shù)(Constructors)
  • 聲明一個和類名相同的函數(shù),來作為類的構造函數(shù)。
  class Point {
     num x;
     num y;

     Point(num x, num y) {
        // There's a better way to do this, stay tuned.
        this.x = x;
        this.y = y;
     }
  }

  • this關鍵字指向了當前類的實例, 上面的代碼可以簡化為:
 class Point {
    num x;
    num y;

    // Syntactic sugar for setting x and y
    // before the constructor body runs.
    Point(this.x, this.y);
 }

  1. 構造函數(shù)不能繼承(Constructors aren’t inherited)
  • Dart 語言中,子類不會繼承父類的命名構造函數(shù)。如果不顯式提供子類的構造函數(shù),系統(tǒng)就提供默認的構造函數(shù)。
  1. 命名的構造函數(shù)(Named constructors)
  • 使用命名構造函數(shù)從另一類或現(xiàn)有的數(shù)據(jù)中快速實現(xiàn)構造函數(shù)。
class Point {
   num x;
   num y;

   Point(this.x, this.y);

   // 命名構造函數(shù)Named constructor
   Point.fromJson(Map json) {
     x = json['x'];
     y = json['y'];
   }
}

  • 構造函數(shù)不能被繼承,父類中的命名構造函數(shù)不能被子類繼承。如果想要子類也擁有一個父類一樣名字的構造函數(shù),必須在子類是實現(xiàn)這個構造函數(shù)。
  1. 調用父類的非默認構造函數(shù)
  • 默認情況下,子類只能調用父類的無名,無參數(shù)的構造函數(shù); 父類的無名構造函數(shù)會在子類的構造函數(shù)前調用; 如果initializer list 也同時定義了,則會先執(zhí)行initializer list 中的內容,然后在執(zhí)行父類的無名無參數(shù)構造函數(shù),最后調用子類自己的無名無參數(shù)構造函數(shù)。即下面的順序:

    1. initializer list(初始化列表)
    2. super class’s no-arg constructor(父類無參數(shù)構造函數(shù))
    3. main class’s no-arg constructor (主類無參數(shù)構造函數(shù))
  • 如果父類不顯示提供無名無參數(shù)構造函數(shù)的構造函數(shù),在子類中必須手打調用父類的一個構造函數(shù)。這種情況下,調用父類的構造函數(shù)的代碼放在子類構造函數(shù)名后,子類構造函數(shù)體前,中間使用:(colon) 分割。

    class Person {
       String firstName;
    
       Person.fromJson(Map data) {
           print('in Person');
       }
    }
    
    class Employee extends Person {
       // 父類沒有無參數(shù)的非命名構造函數(shù),必須手動調用一個構造函數(shù)     
       super.fromJson(data)
       Employee.fromJson(Map data) : super.fromJson(data) {
          print('in Employee');
       }
    }
    
    main() {
       var emp = new Employee.fromJson({});
    
       // Prints:
       // in Person
       // in Employee
       if (emp is Person) {
         // Type check
         emp.firstName = 'Bob';
       }
       (emp as Person).firstName = 'Bob';
    }
    
    
  1. 初始化列表

    • 除了調用父類的構造函數(shù),也可以通過初始化列表在子類的構造函數(shù)體前(大括號前)來初始化實例的變量值,使用逗號,分隔。如下所示:
    class Point {
       num x;
       num y;
    
       Point(this.x, this.y);
    
       // 初始化列表在構造函數(shù)運行前設置實例變量。
       Point.fromJson(Map jsonMap)
       : x = jsonMap['x'],
         y = jsonMap['y'] {
          print('In Point.fromJson(): ($x, $y)');
       }
     }
    
    

    注意:上述代碼,初始化程序無法訪問 this 關鍵字。

  2. 靜態(tài)構造函數(shù)

    • 如果你的類產生的對象永遠不會改變,你可以讓這些對象成為編譯時常量。為此,需要定義一個 const 構造函數(shù)并確保所有的實例變量都是 final 的。
    
    class ImmutablePoint {
        final num x;
        final num y;
        const ImmutablePoint(this.x, this.y);
        static final ImmutablePoint origin = const ImmutablePoint(0, 0);
    }
    
    
  3. 重定向構造函數(shù)

    • 有時候構造函數(shù)的目的只是重定向到該類的另一個構造函數(shù)。重定向構造函數(shù)沒有函數(shù)體,使用冒號:分隔。
    class Point {
        num x;
        num y;
    
        // 主構造函數(shù)
        Point(this.x, this.y) {
            print("Point($x, $y)");
        }
    
        // 重定向構造函數(shù),指向主構造函數(shù),函數(shù)體為空
        Point.alongXAxis(num x) : this(x, 0);
    }
    
    void main() {
        var p1 = new Point(1, 2);
        var p2 = new Point.alongXAxis(4);
    }
    
    
  4. 常量構造函數(shù)

  • 如果類的對象不會發(fā)生變化,可以構造一個編譯時的常量構造函數(shù)。定義格式如下:

    • 定義所有的實例變量是final。
    • 使用const聲明構造函數(shù)。
class ImmutablePoint {
   final num x;
   final num y;
   const ImmutablePoint(this.x, this.y);
   static final ImmutablePoint origin = const ImmutablePoint(0, 0);
}

  1. 工廠構造函數(shù)
  • 當實現(xiàn)一個使用 factory 關鍵詞修飾的構造函數(shù)時,這個構造函數(shù)不必創(chuàng)建類的新實例。例如,工廠構造函數(shù)可能從緩存返回實例,或者它可能返回子類型的實例。 下面的示例演示一個工廠構造函數(shù)從緩存返回的對象:

class Logger {
   final String name;
   bool mute = false;

   // _cache 是一個私有庫,幸好名字前有個 _ 。 
   static final Map<String, Logger> _cache = <String, Logger>{};

   factory Logger(String 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);
       }
    }
    
 }

注意:工廠構造函數(shù)不能用 this。

方法

  • 方法就是為對象提供行為的函數(shù)。
  1. 實例方法

    • 對象的實例方法可以訪問實例變量和 this 。以下示例中的 distanceTo() 方法是實例方法的一個例子:
    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);
       }
     }
    
    
  2. setters 和 Getters

    • 是一種提供對方法屬性讀和寫的特殊方法。每個實例變量都有一個隱式的 getter 方法,合適的話可能還會有 setter 方法。你可以通過實現(xiàn) getters 和 setters 來創(chuàng)建附加屬性,也就是直接使用 get 和 set 關鍵詞:
    class Rectangle {
       num left;
       num top;
       num width;
       num height;
    
       Rectangle(this.left, this.top, this.width, this.height);
    
       // 定義兩個計算屬性: right and 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);
    }
    
    
    • 借助于 getter 和 setter ,你可以直接使用實例變量,并且在不改變客戶代碼的情況下把他們包裝成方法。

    • 注: 不論是否顯式地定義了一個 getter,類似增量(++)的操作符,都能以預期的方式工作。為了避免產生任何向著不期望的方向的影響,操作符一旦調用 getter ,就會把他的值存在臨時變量里。

  1. 抽象方法

    • Instance , getter 和 setter 方法可以是抽象的,也就是定義一個接口,但是把實現(xiàn)交給其他的類。要創(chuàng)建一個抽象方法,使用分號(;)代替方法體:
     abstract class Doer {
        // ...定義實例變量和方法...
        void doSomething(); // 定義一個抽象方法。
     }
    
     class EffectiveDoer extends Doer {
         void doSomething() {
            // ...提供一個實現(xiàn),所以這里的方法不是抽象的...
         }
     }
    
    
  2. 枚舉類型

  • 枚舉類型,通常被稱為 enumerations 或 enums ,是一種用來代表一個固定數(shù)量的常量的特殊類。

  • 聲明一個枚舉類型需要使用關鍵字 enum :

     enum Color {
        red,
        green,
        blue
     }
    
    
  • 在枚舉中每個值都有一個 index getter 方法,它返回一個在枚舉聲明中從 0 開始的位置。例如,第一個值索引值為 0 ,第二個值索引值為 1 。

  assert(Color.red.index == 0);
  assert(Color.green.index == 1);
  assert(Color.blue.index == 2);

  • 要得到枚舉列表的所有值,可使用枚舉的 values 常量。
```
  List<Color> colors = Color.values;
  assert(colors[2] == Color.blue);   

```

* 你可以在 switch 語句 中使用枚舉。如果 e 在 switch (e) 是顯式類型的枚舉,那么如果你不處理所有的枚舉值將會彈出警告:

 ```
  enum Color {
     red,
     green,
     blue
  }
  // ...
  Color aColor = Color.blue;
  switch (aColor) {
      case Color.red:
         print('Red as roses!');
         break;
         
      case Color.green:
         print('Green as grass!');
         break;
    
      default: // Without this, you see a WARNING.
         print(aColor);  // 'Color.blue'
   }
 
 ```

***枚舉類型有以下限制***
   * 你不能在子類中混合或實現(xiàn)一個枚舉。
   * 你不能顯式實例化一個枚舉。
  1. 為類添加特征:mixins

    • mixins 是一種多類層次結構的類的代碼重用。

    • 要使用 mixins ,在 with 關鍵字后面跟一個或多個 mixin 的名字。下面的例子顯示了兩個使用mixins的類:

     class Musician extends Performer with Musical {
          // ...
     }
    
    class Maestro extends Person with Musical, 
        Aggressive, Demented {
    
           Maestro(String maestroName) {
               name = maestroName;
               canConduct = true;
           }
     }
    
    
  • 要實現(xiàn) mixin ,就創(chuàng)建一個繼承 Object 類的子類,不聲明任何構造函數(shù),不調用 super 。例如:

     abstract class Musical {
        bool canPlayPiano = false;
        bool canCompose = false;
        bool canConduct = false;
    
       void entertainMe() {
         if (canPlayPiano) {
             print('Playing piano');
         } else if (canConduct) {
             print('Waving hands');
         } else {
             print('Humming to self');
         }
       }
     }
    
    
  1. 類的變量和方法

    • 使用 static 關鍵字來實現(xiàn)類變量和類方法。

    • 只有當靜態(tài)變量被使用時才被初始化。

    • 靜態(tài)變量, 靜態(tài)變量(類變量)對于類狀態(tài)和常數(shù)是有用的:

        class Color {
           static const red = const Color('red'); // 一個恒定的靜態(tài)變量
           final String name;      // 一個實例變量。 
           const Color(this.name); // 一個恒定的構造函數(shù)。
        }
      
        main() {
           assert(Color.red.name == 'red');
        }
      
      
    • 靜態(tài)方法, 靜態(tài)方法(類方法)不在一個實例上進行操作,因而不必訪問 this 。例如:

      import 'dart:math';
    
      class Point {
         num x;
         num y;
         Point(this.x, this.y);
    
         static num distanceBetween(Point a, Point b) {
            var dx = a.x - b.x;
            var dy = a.y - b.y;
            return sqrt(dx * dx + dy * dy);
         }
      }
    
      main() {
        var a = new Point(2, 2);
        var b = new Point(4, 4);
        var distance = Point.distanceBetween(a, b);
        assert(distance < 2.9 && distance > 2.8);
      }
    
    
    • 注:考慮到使用高階層的方法而不是靜態(tài)方法,是為了常用或者廣泛使用的工具和功能。

    • 你可以將靜態(tài)方法作為編譯時常量。例如,你可以把靜態(tài)方法作為一個參數(shù)傳遞給靜態(tài)構造函數(shù)。

抽象類

  • 使用 abstract 修飾符來定義一個抽象類,該類不能被實例化。抽象類在定義接口的時候非常有用,實際上抽象中也包含一些實現(xiàn)。如果你想讓你的抽象類被實例化,請定義一個 工廠構造函數(shù) 。

  • 抽象類通常包含 抽象方法。下面是聲明一個含有抽象方法的抽象類的例子:

     // 這個類是抽象類,因此不能被實例化。
     abstract class AbstractContainer {
       // ...定義構造函數(shù),域,方法...
    
       void updateChildren(); // 抽象方法。
     }
    
    
  • 下面的類不是抽象類,因此它可以被實例化,即使定義了一個抽象方法:

     class SpecializedContainer extends AbstractContainer {
        // ...定義更多構造函數(shù),域,方法...
    
        void updateChildren() {
          // ...實現(xiàn) updateChildren()...
        }
    
       // 抽象方法造成一個警告,但是不會阻止實例化。
       void doSomething();
     }
    
    

類-隱式接口

  • 每個類隱式的定義了一個接口,含有類的所有實例和它實現(xiàn)的所有接口。如果你想創(chuàng)建一個支持類 B 的 API 的類 A,但又不想繼承類 B ,那么,類 A 應該實現(xiàn)類 B 的接口。

  • 一個類實現(xiàn)一個或更多接口通過用 implements 子句聲明,然后提供 API 接口要求。例如:

    
     // 一個 person ,包含 greet() 的隱式接口。
     class Person {
         // 在這個接口中,只有庫中可見。
         final _name;
    
         // 不在接口中,因為這是個構造函數(shù)。
         Person(this._name);
    
         // 在這個接口中。
         String greet(who) => 'Hello, $who. I am $_name.';
     }
    
     //  Person 接口的一個實現(xiàn)。
     class Imposter implements Person {
         // 我們不得不定義它,但不用它。
         final _name = "";
    
         String greet(who) => 'Hi $who. Do you know who I am?';
     }
    
     greetBob(Person person) => person.greet('bob');
    
     main() {
        print(greetBob(new Person('kathy')));
        print(greetBob(new Imposter()));
     }
    
    
    • 這里是具體說明一個類實現(xiàn)多個接口的例子:

       class Point implements Comparable, Location {
          // ...
       }
      
      

類-擴展一個類

  • 使用 extends 創(chuàng)建一個子類,同時 supper 將指向父類:

     class Television {
        void turnOn() {
           _illuminateDisplay();
            _activateIrSensor();
        }
        // ...
     }
    
     class SmartTelevision extends Television {
        
        void turnOn() {
           super.turnOn();
           _bootNetworkInterface();
           _initializeMemory();
           _upgradeApps();
        }
        // ...
     }
    
    
  • 子類可以重載實例方法, getters 方法, setters 方法。下面是個關于重寫 Object 類的方法 noSuchMethod() 的例子,當代碼企圖用不存在的方法或實例變量時,這個方法會被調用。

      class A {
        // 如果你不重寫 noSuchMethod 方法, 就用一個不存在的成員,會導致NoSuchMethodError 錯誤。
        void noSuchMethod(Invocation mirror) {
            print('You tried to use a non-existent member:' + 
                '${mirror.memberName}');
         }
      }
    
    
    
  • 你可以使用 @override 注釋來表明你重寫了一個成員。

     class A {
        @override
        void noSuchMethod(Invocation mirror) {
           // ...
        }
     }
    
    
    • 如果你用 noSuchMethod() 實現(xiàn)每一個可能的 getter 方法,setter 方法和類的方法,那么你可以使用 @proxy 標注來避免警告。
     @proxy
     class A {
        void noSuchMethod(Invocation mirror) {
            // ...
        }
     }
    
    

庫和可見性

  1. import,part,library指令可以幫助創(chuàng)建一個模塊化的,可共享的代碼庫。庫不僅提供了API,還提供隱私單元:以下劃線(_)開頭的標識符只對內部庫可見。每個Dartapp就是一個庫,即使它不使用庫指令。

  2. 庫可以分布式使用包。見 Pub Package and Asset Manager 中有關pub(SDK中的一個包管理器)。

  3. 使用庫

  • 使用 import 來指定如何從一個庫命名空間用于其他庫的范圍。

  • 例如,Dart Web應用一般采用這個庫 dart:html,可以這樣導入:

  import 'dart:html';

  • 唯一需要 import 的參數(shù)是一個指向庫的 URI。對于內置庫,URI中具有特殊dart:scheme。對于其他庫,你可以使用文件系統(tǒng)路徑或package:scheme。包 package:scheme specifies libraries ,如pub工具提供的軟件包管理器庫。例如:
  import 'dart:io';
  import 'package:mylib/mylib.dart';
  import 'package:utils/utils.dart';

  1. 指定庫前綴
  • 如果導入兩個庫是有沖突的標識符,那么你可以指定一個或兩個庫的前綴。例如,如果 library1 和 library2 都有一個元素類,那么你可能有這樣的代碼:
```
  import 'package:lib1/lib1.dart';
  import 'package:lib2/lib2.dart' as lib2;
  // ...
  var element1 = new Element(); // 使用lib1里的元素
  var element2 =
  new lib2.Element();  // 使用lib2里的元素

```   
  1. 導入部分庫

    • 如果想使用的庫一部分,你可以選擇性導入庫。例如:
     // 只導入foo庫
     import 'package:lib1/lib1.dart' show foo;
    
     //導入所有除了foo
     import 'package:lib2/lib2.dart' hide foo;
    
    
  2. 延遲加載庫

    • 延遲(deferred)加載(也稱為延遲(lazy)加載)允許應用程序按需加載庫。下面是當你可能會使用延遲加載某些情況:

      • 為了減少應用程序的初始啟動時間;
      • 執(zhí)行A / B測試-嘗試的算法的替代實施方式中;
      • 加載很少使用的功能,例如可選的屏幕和對話框。
    • 為了延遲加載一個庫,你必須使用 deferred as 先導入它。

       import 'package:deferred/hello.dart' deferred as hello;
       
      
    • 當需要庫時,使用該庫的調用標識符調用 LoadLibrary()。

       greet() async {
         await hello.loadLibrary();
         hello.printGreeting();
       }
      
      
    • 在前面的代碼,在庫加載好之前,await關鍵字都是暫停執(zhí)行的。有關 async 和 await 見 asynchrony support 的更多信息。

    • 您可以在一個庫調用 LoadLibrary() 多次都沒有問題。該庫也只被加載一次。

    • 當您使用延遲加載,請記住以下內容:

      • 延遲庫的常量在其作為導入文件時不是常量。記住,這些常量不存在,直到遲庫被加載完成。
      • 你不能在導入文件中使用延遲庫常量的類型。相反,考慮將接口類型移到同時由延遲庫和導入文件導入的庫。
      • Dart隱含調用LoadLibrary()插入到定義deferred as namespace。在調用LoadLibrary()函數(shù)返回一個Future。
  1. 庫的實現(xiàn)

    • 用 library 來來命名庫,用part來指定庫中的其他文件。 注意:不必在應用程序中(具有頂級main()函數(shù)的文件)使用library,但這樣做可以讓你在多個文件中執(zhí)行應用程序。
  1. 聲明庫

    • 利用library identifier(庫標識符)指定當前庫的名稱:

        // 聲明庫,名ballgame
        library ballgame;
      
        // 導入html庫
        import 'dart:html';
      
        // ...代碼從這里開始... 
      
      
  1. 關聯(lián)文件與庫

    • 添加實現(xiàn)文件,把part fileUri放在有庫的文件,其中fileURI是實現(xiàn)文件的路徑。然后在實現(xiàn)文件中,添加部分標識符(part of identifier),其中標識符是庫的名稱。下面的示例使用的一部分,在三個文件來實現(xiàn)部分庫。

    • 第一個文件,ballgame.dart,聲明球賽庫,導入其他需要的庫,并指定ball.dart和util.dart是此庫的部分:

        library ballgame;
      
        import 'dart:html';
        // ...其他導入在這里...
      
        part 'ball.dart';
        part 'util.dart';
      
        // ...代碼從這里開始...
      
      
  • 第二個文件ball.dart,實現(xiàn)了球賽庫的一部分:

     part of ballgame;
    
     // ...代碼從這里開始...
    
    
  • 第三個文件,util.dart,實現(xiàn)了球賽庫的其余部分:

     part of ballgame;
    
     // ...Code goes here...
    
    
  1. 重新導出庫(Re-exporting libraries)
* 可以通過重新導出部分庫或者全部庫來組合或重新打包庫。例如,你可能有實現(xiàn)為一組較小的庫集成為一個較大庫。或者你可以創(chuàng)建一個庫,提供了從另一個庫方法的子集。

  ```
   // In french.dart:
   library french;

   hello() => print('Bonjour!');
   goodbye() => print('Au Revoir!');

   // In togo.dart:
   library togo;

   import 'french.dart';
   export 'french.dart' show hello;

   // In another .dart file:
   import 'togo.dart';

   void main() {
       hello();   //print bonjour
       goodbye(); //FAIL
   }
  
  ```

異步的支持

  1. Dart 添加了一些新的語言特性用于支持異步編程。最通常使用的特性是 async 方法和 await 表達式。Dart 庫大多方法返回 Future 和 Stream 對象。這些方法是異步的:它們在設置一個可能的耗時操作(比如 I/O 操作)之后返回,而無需等待操作完成

  2. 當你需要使用 Future 來表示一個值時,你有兩個選擇。

    • 使用 async 和 await
    • 使用 Future API
  3. 同樣的,當你需要從 Stream 獲取值的時候,你有兩個選擇。

    • 使用 async 和一個異步的 for 循環(huán) (await for)
    • 使用 Stream API
  4. 使用 async 和 await 的代碼是異步的,不過它看起來很像同步的代碼。比如這里有一段使用 await 等待一個異步函數(shù)結果的代碼:

await lookUpVersion()

  1. 要使用 await,代碼必須用 await 標記

     checkVersion() async {
        var version = await lookUpVersion();
        if (version == expectedVersion) {
           // Do something.
        } else {
          // Do something else.
          }
     }
    
    
  2. 你可以使用 try, catch, 和 finally 來處理錯誤并精簡使用了 await 的代碼。

    
     try {
        server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 4044);
     } catch (e) {
        // React to inability to bind to the port...
     }
    
    
  3. 聲明異步函數(shù)

  • 一個異步函數(shù)是一個由 async 修飾符標記的函數(shù)。雖然一個異步函數(shù)可能在操作上比較耗時,但是它可以立即返回-在任何方法體執(zhí)行之前。

     checkVersion() async {
        // ...
     }
    
     lookUpVersion() async => /* ... */;
    
    
  • 在函數(shù)中添加關鍵字 async 使得它返回一個 Future,比如,考慮一下這個同步函數(shù),它將返回一個字符串。

  • String lookUpVersionSync() => '1.0.0';

  • 如果你想更改它成為異步方法-因為在以后的實現(xiàn)中將會非常耗時-它的返回值是一個 Future 。

  • Future<String> lookUpVersion() async => '1.0.0';

  • 請注意函數(shù)體不需要使用 Future API,如果必要的話 Dart 將會自己創(chuàng)建 Future 對象

  1. 使用帶 future 的 await 表達式
  • 一個 await表達式具有以下形式

    await expression

  • 在異步方法中你可以使用 await 多次。比如,下列代碼為了得到函數(shù)的結果一共等待了三次。

     var entrypoint = await findEntrypoint();
     var exitCode = await runExecutable(entrypoint, args);
     await flushThenExit(exitCode);
    
    
  • await 表達式中, 表達式 的值通常是一個 Future 對象;如果不是,那么這個值會自動轉為 Future。這個 Future 對象表明了表達式應該返回一個對象。await 表達式 的值就是返回的一個對象。在對象可用之前,await 表達式將會一直處于暫停狀態(tài)。

  • 如果 await 沒有起作用,請確認它是一個異步方法。比如,在你的 main() 函數(shù)里面使用await,main() 的函數(shù)體必須被 async 標記:

 ```
  main() async {
     checkVersion();
     print('In main: version is ${await lookUpVersion()}');
  }
 
 ```
  1. 結合 streams 使用異步循環(huán)

    • 一個異步循環(huán)具有以下形式:
     await for (variable declaration in expression) {
         // Executes each time the stream emits a value.
     }
    
    
    • 表達式 的值必須有Stream 類型(流類型)。執(zhí)行過程如下:

      • 在 stream 發(fā)出一個值之前等待
      • 執(zhí)行 for 循環(huán)的主體,把變量設置為發(fā)出的值。
      • 重復 1 和 2,直到 Stream 關閉
    • 如果要停止監(jiān)聽 stream ,你可以使用 break 或者 return 語句,跳出循環(huán)并取消來自 stream 的訂閱 。

    • 如果一個異步 for 循環(huán)沒有正常運行,請確認它是一個異步方法。 比如,在應用的 main() 方法中使用異步的 for 循環(huán)時,main() 的方法體必須被 async 標記。

      main() async {
         ...
        
         await for (var request in requestServer) {
             handleRequest(request);
         }
      
         ...
      }
    
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 此文章是v1.0+時編寫,年代久遠,小心有毒,謹慎食用!!! 一些重要概念 所有的東西都是對象,所有的對象都是類的...
    soojade閱讀 10,114評論 2 27
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,778評論 18 399
  • 前言 人生苦多,快來 Kotlin ,快速學習Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,282評論 9 118
  • 花看半開,當數(shù)含笑詮釋的完美。 一半的心態(tài)面對世俗…… 一半的內心燃燒夢想,一半的內心與命運握手言和。 酒飲微醉,...
    芷蘭鳳吟閱讀 296評論 1 1
  • 看見不健全的人格,我總是急于用內心的柔軟感化,這種不自覺的人格綁架,讓我常常把自己定位為一個擺渡人。而誰將渡我...
    攖寧7閱讀 313評論 0 1