Dart的語法詳解系列篇(四)-- 泛型璃饱、異步、庫等有關詳解

版權(quán)聲明:本文為博主原創(chuàng)文章肪康,未經(jīng)博主允許不得轉(zhuǎn)載荚恶。http://www.reibang.com/p/a4a9c89b85ca

轉(zhuǎn)載請標明出處:
http://www.reibang.com/p/a4a9c89b85ca
本文出自 AWeiLoveAndroid的博客


本文首發(fā)在公眾號Flutter那些事撩穿,未經(jīng)允許,嚴禁轉(zhuǎn)載谒撼。

前言
Flutter1.0穩(wěn)定版昨晚的終于發(fā)布了食寡。我們?yōu)榇烁械礁吲d。對于開發(fā)者來說廓潜,有了穩(wěn)定版相當于一個定心丸抵皱。本文主要介紹Fllutter1.0的一些功能和相關工具。


Flutter系列博文鏈接 ↓:

工具安裝:

Flutter基礎篇:

Flutter進階篇:

Dart語法系列博文鏈接 ↓:

Dart語法基礎篇:

Dart語法進階篇:


本文代碼同步發(fā)布在Github: https://github.com/AweiLoveAndroid/Flutter-learning/tree/master/projects/dart_demo

上一篇主要講了Dart的類與函數(shù)樱蛤,由于內(nèi)容有太多,我就把剩下的內(nèi)容分開寫一篇文章剑鞍。
這一篇我們講Dart的泛型昨凡、異步、庫等有關詳解蚁署,內(nèi)容較多便脊,希望大家可以耐心看完。我也是花了很長時間研究的光戈。喜歡的就點個贊哪痰,打個賞吧。
感謝大家支持久妆。


九晌杰、泛型(Generics)

如果您查看基本數(shù)組類型的API文檔 List,您會看到該類型實際上是List<E>筷弦。<...>表示法將List標記為 泛型(或參數(shù)化)類型 - 具有正式類型參數(shù)的類型肋演。按照慣例,大多數(shù)類型變量都有單字母名稱烂琴,例如E爹殊,T,S奸绷,K和V.

(一)為什么使用泛型梗夸?

類型安全通常需要泛型,但它們比僅允許代碼運行有更多好處:

1).正確指定泛型類型可以生成更好的代碼健盒。

如果您希望列表只包含字符串绒瘦,則可以將其聲明為List<String>(將其讀作“字符串列表”)称簿。這樣一來,工具可以檢測到將非字符串分配給列表可能是一個錯誤惰帽。
例子:

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
// 報錯 The argument type 'int' can't be assigned to the parameter type 'String'.
names.add(42); 
2).您可以使用泛型來減少代碼重復憨降。

泛型允許您在多種類型之間共享單個接口和實現(xiàn),同時仍然利用靜態(tài)分析该酗。
例如:創(chuàng)建了一個用于緩存對象的接口:

abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}

您發(fā)現(xiàn)需要此接口針對字符串的做一個緩存授药,因此您需要創(chuàng)建另一個接口:

abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}

如果還有其他更改,就要寫很多接口呜魄。
泛型可以省去創(chuàng)建所有這些接口的麻煩悔叽。你可以創(chuàng)建一個帶有類型參數(shù)的接口。
示例如下:T是一個占位符爵嗅,您可以將其視為開發(fā)人員稍后定義的類型娇澎。

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

(二)使用集合文字

list和map文字可以參數(shù)化。參數(shù)化文字就像你已經(jīng)看到的文字一樣睹晒,除了你在開始括號之前添加 <type>(對于list)或 <keyType, valueType>(對于map)趟庄。
以下是使用類型文字(typed literals)的示例:

var numbers = <String>['11', '22', '33'];
var pages = <String, String>{
  'index.html': 'Homepage',
  'store.html': 'Store',
  'mine.html': 'Mine'
};

(三)使用帶有構(gòu)造函數(shù)的參數(shù)化類型

要在使用構(gòu)造函數(shù)時指定一個或多個類型,請將類型放在類名稱后面的尖括號<...>中伪很。例如:

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
var nameSet = Set<String>.from(names);

以下代碼創(chuàng)建一個具有整數(shù)的key和View類型的value的map:

var views = Map<int, View>();

(四)泛型集合及其包含的類型

Dart的泛型類型是具體的戚啥。也就說,它們在運行時會會攜帶類型信息锉试。示例如下:(相反杂瘸,Java中的泛型使用擦除妨蛹,這意味著在運行時刪除泛型類型參數(shù)。在Java中,您可以測試對象是否為List矩欠,但您無法測試它是否是List<String>钮热。)

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
print(names.runtimeType); // List<String>

(五)限制參數(shù)類型

實現(xiàn)泛型類型時髓棋,您可能希望限制其參數(shù)的類型喧锦。你可以在<>里面使用extends。
例如:

abstract class SomeBaseClass {
    // 其他操作
}

class Foo<T extends SomeBaseClass> {
  String toString() {
      return "Instance of Foo<$T>";
  }
}

class Extender extends SomeBaseClass {
     //其他操作
}

現(xiàn)在可以使用SomeBaseClass或它的任何子類作為泛型參數(shù)丁频。

例如:

void main() {
    var someBaseClassFoo = Foo<SomeBaseClass>();
    var extenderFoo = Foo<Extender>();
    print(someBaseClassFoo.toString());// Instance of Foo<SomeBaseClass>
    print(extenderFoo.toString());// Instance of Foo<SomeBaseClass>
}

也可以不指定泛型參數(shù)杉允。
例如:

var foo = Foo();
//等同于print(foo.toString());
print(foo);// Instance of Foo<SomeBaseClass>

如果指定任何非SomeBaseClass類型會導致錯誤。
例如:var foo = Foo<Object>;

(六)使用泛型方法

新版本的Dart的泛型方法席里,允許在方法和函數(shù)上使用類型參數(shù)叔磷。(但它同樣適用于實例方法,靜態(tài)方法奖磁,頂級函數(shù)改基,本地函數(shù)甚至lambda表達式。)
例如:

T first<T>(List<T> data) {
      // 做一些初始工作或錯誤檢查...
      T tmp = data[0];
  // 做一些額外的檢查或處理...
  return tmp;
}

在first(<T>)上的的泛型類型參數(shù)咖为,允許你在以下幾個地方使用類型參數(shù)T:

  • 1). 在函數(shù)的返回類型(T)中
  • 2). 在參數(shù)類型(List<T>)中
  • 3). 在局部變量的類型(T tmp)

泛型方法可以聲明類方法(實例和靜態(tài))以相同的方式獲取泛型參數(shù)秕狰。

class  C {
   static  int f < S稠腊,T > (int x) => 3 ;
  int m < S,T > (int x) => 3 ;
}

泛型方法也適用于函數(shù)類型參數(shù)鸣哀,本地函數(shù)和函數(shù)表達式架忌。

1.將泛型方法作為參數(shù)[callback]。

void  functionTypedParameter(T callback <T>(T thing)){}

2.聲明一個本地泛型函數(shù)本身我衬。

void  localFunction(){
   T itself<T>(T thing) => thing;
}

3.將泛型函數(shù)表達式綁定到局部變量叹放。

void functionExpression(){
   var lambda =  <T>(T thing) => thing;
}

十、庫和可見性

該import和library指令可以幫助您創(chuàng)建一個模塊化的挠羔,可共享的代碼庫井仰。庫不僅提供API,還是隱私單元(以下劃線(_)開頭的標識符僅在庫內(nèi)可見)破加。每個Dart應用程序都是一個庫俱恶,即使它不使用library指令“韬恚可以使用包來分發(fā)庫速那。

(一)使用庫

使用import指定一個庫中的命名空間如何在另一個庫匯總使用俐银。
例如尿背,Dart Web應用程序通常使用dart:html 庫,它們可以像這樣導入:
import 'dart:html';
對于內(nèi)置庫捶惜,URI具有特殊dart: 方案(scheme)田藐。對于其他庫,您可以使用文件系統(tǒng)路徑或package: 方案(scheme)吱七,這個是由包管理器(如pub工具)提供的庫汽久。
例如:
import 'libs/mylib.dart';

(二)指定庫前綴

如果導入兩個具有沖突標識符的庫,則可以為一個或兩個庫指定前綴踊餐。例如景醇,如果test2.dart和test3.dart都有一個hello()函數(shù),那么直接導入這兩個文件會有沖突吝岭,這種情況下我們可以使用as關鍵字給庫指定一個前綴:

test2.dart代碼如下:

void hello() {
  print('test2.dart : hello()函數(shù)');
}

test3.dart代碼如下:
void hello(){
  print('test3.dart : hello()函數(shù)');
}

現(xiàn)在要在test1.dart中導入這兩個文件:
// 這樣寫會報錯
// import 'test2.dart';
// import 'test3.dart';
    
  // 正確寫法:
import 'test2.dart';
// 給導入的庫指定一個前綴 方便識別
import 'test3.dart' as test3;
  
  調(diào)用方式:
  void main(){
    hello();//test2.dart : hello()函數(shù)
    test3.hello();//test3.dart : hello()函數(shù)
}

導入庫也可以使用相對路徑三痰。例如:lib/demo1/a.dart, lib/demo2/b.dart這兩個文件。現(xiàn)在b.dart這個文件需要引用a.dart窜管,可以使用import '../demo1/a.dart'導入散劫。

(三)僅導入庫的一部分

如果只想使用庫的一部分,則可以有選擇地導入庫幕帆,可以使用show或者hide關鍵字获搏。例如:show表示僅導入當前庫,hide表示除了當前庫之外全部導入失乾。

// 僅導入mylib.dart里面的test2函數(shù)
// import 'libs/mylib.dart' show test2;
// 剛好和show相反 除了test2函數(shù)之外  其它的都導入
import 'libs/mylib.dart' hide test2;
//我們想導入mylib庫常熙,但是不想用里面的otherLib這個庫 可以這樣寫
// import 'libs/mylib.dart' hide otherLib;

(四)懶加載一個庫

延遲加載(也稱為延遲加載)允許應用程序根據(jù)需要加載庫纬乍,如果需要的話。以下是您可能使用延遲加載的一些情況:

  • 1).減少應用程序的初始啟動時間裸卫。
  • 2).例如蕾额,執(zhí)行A/B測試 - 嘗試算法的替代實現(xiàn)。
  • 3).加載很少使用的功能彼城,例如可選的屏幕和對話框诅蝶。
    要延遲加載庫,必須先使用deferred as它導入一個庫募壕。當我們import一個庫的時候调炬,如果使用了as 不能同時使用deferred as
    例如:
// import 'libs/mylib.dart'; // 不能同時使用
import 'libs/mylib.dart' deferred as tests;

當您需要庫時,使用庫的標識符調(diào)用loadLibrary()舱馅。
例如(注意導包:import 'dart:async';):

Future hello() async {
  await tests.loadLibrary();
  tests.test2();
}
// 然后再去使用:
void main(){
  hello(); // 結(jié)果是: mylib.dart:test2()函數(shù)
}

在上述的代碼中缰泡,await關鍵字暫停執(zhí)行,直到庫被加載代嗤。
您可以在一個庫上調(diào)用loadLibrary()多次棘钞,而不會出現(xiàn)問題。該庫只加載一次干毅。

使用延遲加載時請記住以下內(nèi)容:

  • 1).延遲庫的常量不是導入文件中的常量宜猜。請記住,在加載延遲庫之前硝逢,這些常量不存在姨拥。
  • 2).您不能在導入文件中使用延遲庫中的類型。相反渠鸽,請考慮將接口類型移動到由延遲庫和導入文件導入的*庫叫乌。
  • 3).Dart隱式插入loadLibrary()到你使用deferred as namespace定義的命名空間。loadLibrary()函數(shù)返回Future徽缚。

(五)庫的拆分

【說明】dart官網(wǎng)不推薦使用part 憨奸,這個僅作為了解。
使用part指令凿试,可以將庫拆分為多個Dart文件排宰。part of表示隸屬于某個庫的一部分。
注意事項:

  • 1.不能同時使用library和part of红省,它們都用于指定屬于庫的內(nèi)容额各。
// library testlib2; 這個不能和part of同時使用 會報錯
// part of 表示這個庫是testlib庫的一部分
part of testlib1;
    1. B庫是A庫的一部分,在B庫里面聲明:part of A庫名稱
      例如:在testlib2.dart里面聲明 part of testlib1; 表示testlib2這個庫是testlib庫的yi部分吧恃。
    1. 如果B庫聲明A庫的一部分虾啦,同時A庫也想聲明它的一部分是B庫,正確寫法:B庫聲明part of A庫名稱,然后A庫聲明part 'B庫的路徑' , 同時傲醉,如果B庫沒有聲明蝇闭,那么在A庫里面使用part指令會報錯。
      testlib1.dart內(nèi)容:
// 第1個庫:
library testlib1;
// 可以不寫
part 'testlib2.dart';
void run() {
  print('testlib1庫 : run()函數(shù)');
}

testlib2.dart內(nèi)容:

part of testlib1;
class testLib2 {}
void start() {
  print('testlib2庫 : start()函數(shù)');
}
    1. B庫聲明了part of A庫名稱硬毕,A庫可以省去聲明part 'B庫的路徑'
// 第1個庫:
library testlib1;
// 可以不寫
part 'testlib2.dart';

(六)庫的自動導入

在A庫中使用export關鍵字引入B庫呻引,當我們使用A庫的時候,會自動引入B庫吐咳,也就是說我們導入了A庫逻悠,就可以使用B庫了。
mylib.dart內(nèi)容為:

// 這是一個庫 命名為mylib
library mylib;
// 希望使用mylib的時候 自動使用otherlib.dart  可以使用export關鍵字引入其他庫
export 'otherlib.dart';
// 導入otherlib2.dart
export 'otherlib2.dart';

class MyLib {
  void test() {
    print('mylib.dart: MyLib : test()函數(shù)');
  }
}

void test2() {
  print('mylib.dart: test2()函數(shù)');
}

otherlib.dart庫內(nèi)容為:

// otherlib庫
library otherlib;
class otherLib {}
void test() {
  print('otherLib庫 : test()函數(shù)');
}

otherlib2.dart庫內(nèi)容為:

// otherlib2庫
library otherlib2;
class otherLib2 {}
void test2() {
  print('otherLib2庫 : test2()函數(shù)');
}

(七)庫的組成結(jié)構(gòu)

庫的最低要求是:pubspec.yaml文件和lib目錄韭脊。
庫的pubspec.yaml文件與普通應用程序包的文件格式相同童谒。
lib目錄:庫代碼位于lib 目錄下,并且對其他包是公共的沪羔。您可以根據(jù)需要在lib下創(chuàng)建任何層次結(jié)構(gòu)饥伊。
聲明一個庫的關鍵字是library。
例如在文件test.dart文件首行加上:library mylib; 表示這個庫的名稱是mylib


十一蔫饰、異步支持

Dart庫中包含許多返回Future或Stream對象的函數(shù)琅豆。這些函數(shù)是異步的:它們在設置可能耗時的操作(例如I / O)后返回,而不等待該操作完成篓吁。

Dart官網(wǎng)有關于異步的教學:
使用Future完成異步任務:https://www.dartlang.org/tutorials/language/futures
使用Streams(流)管理序列化數(shù)據(jù):https://www.dartlang.org/tutorials/language/streams

asyncawait關鍵字支持異步編程茫因,讓你寫異步代碼看起來類似于同步代碼。

(一)處理Future

當您需要完成Future的結(jié)果時越除,您有兩個選擇:

  • 1).使用async和await节腐。
  • 2).使用Future API,如 庫瀏覽 中所述摘盆。

(二)使用async和await

使用asyncawait異步的代碼,但它看起來很像同步代碼饱苟。例如孩擂,這里有一些代碼await 用于等待異步函數(shù)的結(jié)果。例如:await lookUpVersion();

要使用async箱熬,代碼必須在async函數(shù)中(標記為async的函數(shù))类垦。
例如:

Future checkVersion() async {
  var version = await lookUpVersion();
  // 其他操作
}

注意: 雖然async函數(shù)可能執(zhí)行耗時的操作,但它不會等待這些操作城须。async函數(shù)只在遇到第一個await表達式時執(zhí)行蚤认。然后它返回一個Future對象,僅在await表達式完成后才恢復執(zhí)行糕伐。

使用try砰琢,catch,finally在使用await的代碼中處理錯誤和清理代碼。

try {
  var version = await lookUpVersion();
} catch (e) {
  // 這里可以看到是什么錯誤陪汽。
}finally{
  // 正確的解決方式寫在這里
}

您可以在異步功能中多次使用await训唱。例如,以下代碼等待三次函數(shù)結(jié)果:

var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);

在await表達式中挚冤,表達式的值通常是Future; 如果不是况增,那么該值將自動包含在Future中。 這個Future對象表示返回一個對象的promise训挡。 await表達式的值是返回的對象澳骤。 await表達式使執(zhí)行暫停,直到該對象可用澜薄。

如果在使用await時遇到編譯時錯誤宴凉,請確保await在async函數(shù)中。
例如表悬,要在應用程序的main()函數(shù)中使用await弥锄,main()方法必須標記為async:以下是一個完整的示例代碼:

import 'dart:async';

Future main() async {
  checkVersion();
  print('In main: version is ${await lookUpVersion()}');
}

Future checkVersion() async {
  print('checkVersion()');
  var version = await lookUpVersion();
}

Future<String> lookUpVersion() async{
  print('lookUpVersion()');
  return '版本號:v1.0';
}

結(jié)果:

// checkVersion()
// lookUpVersion()
// lookUpVersion()
// In main: version is 版本號:v1.0

(三)定義一個異步函數(shù)

方法被async修飾的函數(shù)是異步函數(shù)。給一個函數(shù)添加async關鍵字蟆沫,使得返回值是一個Future籽暇。

void main(){
  lookUpVersion(); //輸出結(jié)果:lookUpVersion()同步方法 返回值是:1.0.0
  lookUpVersion2(); // 輸出結(jié)果:lookUpVersion2()異步方法 返回值是:1.0.0
  lookUpVersion3(); // 輸出結(jié)果:lookUpVersion3()異步方法 沒有返回值
}

例如,看下面這個返回值是String的同步函數(shù):

String lookUpVersion() {
      print('lookUpVersion()同步方法 返回值是:1.0.0');
      return '1.0.0';
}

如果將其更改為異步函數(shù) - 例如饭庞,因為Future的實現(xiàn)將非常耗時 - 返回的值是Future:

Future<String> lookUpVersion2() async{
      print('lookUpVersion2()異步方法 返回值是:1.0.0');
      return '1.0.0';
}

如果您的函數(shù)沒有返回有用的值戒悠,請設置其返回類型Future<void>
例如:

Future<void> lookUpVersion3() async {
  print('lookUpVersion3()異步方法 沒有返回值');
}

(四)處理Stream

當您需要完成Future的結(jié)果時,您有兩個選擇:

  • 1).使用async和異步for循環(huán)(await for)舟山。
    注意:在使用await for之前绸狐,請確保它使代碼更清晰,并且您確實希望等待所有Stream的結(jié)果累盗。 例如寒矿,通常情況,不應該使用await for UI事件偵聽器若债,因為UI框架會發(fā)送無窮無盡的事件流(streams of events)符相。
  • 2).使用Stream API(主要是IO操作。)

異步for循環(huán)的格式:await for(var或具體類型 標識符 in 表達式){}
例如:我們讀取本地的一個文件內(nèi)容蠢琳,實例代碼如下:

import 'dart:io';
import 'dart:convert';
void main() {
      test();
}
// await for循環(huán)的使用示例
// 這里是讀取本地文件的內(nèi)容
Future test() async {
      var config=File('d:\\test.txt');
      // 打開io流進行文件讀取
      Stream<List<int>> inputStream = config.openRead();
      var lines = inputStream
        // 設置編碼格式為utf-8
        .transform(utf8.decoder)
        .transform(LineSplitter());
      try {
          await for (var line in lines) {
              print('從Stream中獲取到的內(nèi)容是: ${line} \r文本內(nèi)容長度為:'+ '${line.length}\r=======');
          }
        print('文件現(xiàn)在沒有關閉啊终。。傲须。');
      } catch (e) {
        print(e);
      }
}

表達式的值必須有Stream類型蓝牲,執(zhí)行過程如下:

  • 1).等待,知道Stream發(fā)出一個數(shù)值泰讽。
  • 2).執(zhí)行for循環(huán)的主體例衍,講變量設置為這個發(fā)出的數(shù)值昔期。
  • 3).重復1和2,知道關閉Stream肄渗。

要停止監(jiān)聽Stream镇眷,你可以使用break或者return語句跳出for循環(huán)B并且從Stream中取消訂閱。
如果在實現(xiàn)異步for循環(huán)時遇到編譯時錯誤翎嫡,確保await for在一個async函數(shù)中欠动。
例如,要在應用程序的main()函數(shù)中使用await for循環(huán)惑申,main()方法必須標記為async:以下是一個完整的示例代碼:

Future main() async {
   // ...
  await for (var request in requestServer) {
    handleRequest(request);
  }
  // ...
}

有關異步編程的更多信息具伍,請查看庫瀏覽的 Dart庫之旅 --- dart:async 部分,另請參閱文章 Dart語言異步支持:階段2(該頁面可能過期了) 和 Dart語言規(guī)范圈驼。


十二人芽、Isolates

大多數(shù)計算機,甚至在移動平臺上绩脆,都有多核CPU萤厅。為了利用所有這些核心,開發(fā)人員傳統(tǒng)上使用并發(fā)運行的共享內(nèi)存線程靴迫。但是惕味,共享狀態(tài)并發(fā)容易出錯,并且可能導致代碼復雜化玉锌。
所有Dart代碼都在隔離區(qū)內(nèi)運行名挥,而不是線程。每個隔離區(qū)都有自己的內(nèi)存堆主守,確保不會從任何其他隔離區(qū)訪問隔離區(qū)的狀態(tài)禀倔。

Dart是單線程模型,但是使用Isolates可以用于多線程参淫。

這個庫主要用于服務端的開發(fā)救湖。如果你不使用Dart做服務端開發(fā),僅作為了解即可黄刚。
源碼可以看Github:https://github.com/dart-lang/isolate
官方API文檔: https://api.dartlang.org/stable/2.1.0/dart-isolate/dart-isolate-library.html

使用isolate 需要先導入包:import 'dart:isolate';

下面來一個簡單的示例代碼:
// 在另一個隔離區(qū)()中同步讀取“D://file.json”
// 結(jié)果是{msg: [{title: 你好1, contents: yes}, {title: 你好2, contents: NO}]}
main() async {
// 在其他隔離(isolate)中同步讀取文件捎谨,然后對其進行解碼。
print(await readIsolate());
}

// 同步讀取'D//file.json'(在同一個線程中)
Map readSync() {
JsonCodec().decode(new File('D://file.json').readAsStringSync());
}

// 在另一個隔離區(qū)()中同步讀取“D://file.json”
Future readIsolate() async {
final response = new ReceivePort();
await Isolate.spawn(_isolate, response.sendPort);
return response.first;
}

/// 期望通過[Isolate.spawn]創(chuàng)建
void _isolate(SendPort sendPort) {
sendPort.send(readSync());
}

下面是file.json文件的內(nèi)容:
{
"msg": [
{
"title": "你好1",
"contents": "yes"
},
{
"title": "你好2",
"contents": "NO"
}
]
}


十三憔维、生成器(Generators)

當您需要懶惰地生成一系列值時,請考慮使用生成器函數(shù)畏邢。Dart支持兩種生成器功能业扒。

(一)同步生成器,返回一個Iterable對象舒萎。

要實現(xiàn)同步生成器函數(shù)程储,請將函數(shù)體標記為sync*,并使用yield語句來傳遞值。

Iterable<int> naturalsTo(int n) sync* {
  int k = 0;
  while (k < n) yield k++;
}

如果您的生成器是遞歸的章鲤,您可以使用yield*以下方法來提高其性能:

Iterable<int> naturalsDownFrom(int n) sync* {
    if (n > 0) {
      yield n;
      yield* naturalsDownFrom(n - 1);
    }
}

(二)異步生成器摊灭,返回一個Stream對象。

要實現(xiàn)異步生成器函數(shù)败徊,請將函數(shù)體標記為async*帚呼,并使用yield語句來傳遞值。

Stream<int> asynchronousNaturalsTo(int n) async* {
  int k = 0;
  while (k < n) yield k++;
}

十四皱蹦、類型定義

在Dart中煤杀,函數(shù)是對象,就像字符串一樣沪哺,數(shù)字是對象沈自。一個類型定義,或功能型的別名辜妓,給出了一個函數(shù)類型聲明字段時枯途,您可以使用和返回類型的名稱。當函數(shù)類型分配給變量時籍滴,typedef會保留類型信息酪夷。

以下代碼,它不使用typedef:我們可以看到compare是一個函數(shù)异逐,但它是哪一種類型的函數(shù)?不是很清楚捶索。

class SortedCollection {
  Function compare;
  SortedCollection(int f(Object a, Object b)) {
    compare = f;
  }
}

// Initial, broken implementation.
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);

  // compare是一個函數(shù),但它是哪一種類型的函數(shù)?
  assert(coll.compare is Function);
}

接下來使用typedef改造一下:
我們將代碼更改為使用顯式名稱并保留類型信息灰瞻,開發(fā)人員和工具都可以使用該信息腥例。

typedef Compare = int Function(Object a, Object b);

class SortedCollection {
  Compare compare;
  SortedCollection(this.compare);
}

// Initial, broken implementation.
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);
  assert(coll.compare is Function);
  assert(coll.compare is Compare);
}

目前:typedef僅限于函數(shù)類型。

因為typedef只是別名酝润,Dart提供了一種檢查任何函數(shù)類型的方法燎竖。
例如:

typedef Compare<T> = int Function(T a, T b);
int sort(int a, int b) => a - b;
void main() {
  assert(sort is Compare<int>); // True
}

十五、元數(shù)據(jù)Metadata

使用元數(shù)據(jù)提供有關代碼的其他信息要销。元數(shù)據(jù)注解以字符開頭@构回,后跟對編譯時常量(如deprecated)的引用或?qū)ΤA繕?gòu)造函數(shù)的調(diào)用。
元數(shù)據(jù)可以出現(xiàn)在庫疏咐,類纤掸,typedef,類型參數(shù)浑塞,構(gòu)造函數(shù)借跪,工廠,函數(shù)酌壕,字段掏愁,參數(shù)或變量聲明之前以及導入或?qū)С鲋噶钪靶伞D梢允褂梅瓷湓谶\行時檢索元數(shù)據(jù)。
所有Dart代碼都有兩個注解:@deprecated@override果港。
以下是使用@deprecated 注解的示例:

class Television {
  /// _Deprecated: Use [turnOn] instead._
  @deprecated
  void activate() {
    turnOn();
  }

  // Turns the TV's power on.
  void turnOn() {
//...
}
}

您可以定義自己的元數(shù)據(jù)注釋沦泌。

這是一個定義帶有兩個參數(shù)的@todo注釋的示例:

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)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市辛掠,隨后出現(xiàn)的幾起案子谢谦,更是在濱河造成了極大的恐慌,老刑警劉巖公浪,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件他宛,死亡現(xiàn)場離奇詭異,居然都是意外死亡欠气,警方通過查閱死者的電腦和手機厅各,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來预柒,“玉大人队塘,你說我怎么就攤上這事∫搜欤” “怎么了憔古?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長淋袖。 經(jīng)常有香客問我鸿市,道長,這世上最難降的妖魔是什么即碗? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任焰情,我火速辦了婚禮,結(jié)果婚禮上剥懒,老公的妹妹穿的比我還像新娘内舟。我一直安慰自己,他們只是感情好初橘,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布验游。 她就那樣靜靜地躺著,像睡著了一般保檐。 火紅的嫁衣襯著肌膚如雪耕蝉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天夜只,我揣著相機與錄音赔硫,去河邊找鬼。 笑死盐肃,一個胖子當著我的面吹牛爪膊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播砸王,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼推盛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谦铃?” 一聲冷哼從身側(cè)響起耘成,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驹闰,沒想到半個月后瘪菌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡嘹朗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年师妙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屹培。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡默穴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出褪秀,到底是詐尸還是另有隱情蓄诽,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布媒吗,位于F島的核電站仑氛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闸英。R本人自食惡果不足惜锯岖,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望自阱。 院中可真熱鬧嚎莉,春花似錦、人聲如沸沛豌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽加派。三九已至叫确,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芍锦,已是汗流浹背竹勉。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娄琉,地道東北人次乓。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓吓歇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親票腰。 傳聞我的和親對象是個殘疾皇子城看,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345