Dart的語(yǔ)法詳解系列篇(四)-- 泛型、異步、庫(kù)等有關(guān)詳解

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

轉(zhuǎn)載請(qǐng)標(biāo)明出處:
http://www.lxweimin.com/p/a4a9c89b85ca
本文出自 AWeiLoveAndroid的博客


本文首發(fā)在公眾號(hào)Flutter那些事,未經(jīng)允許,嚴(yán)禁轉(zhuǎn)載。

前言
Flutter1.0穩(wěn)定版昨晚的終于發(fā)布了。我們?yōu)榇烁械礁吲d。對(duì)于開發(fā)者來(lái)說(shuō),有了穩(wěn)定版相當(dāng)于一個(gè)定心丸。本文主要介紹Fllutter1.0的一些功能和相關(guān)工具。


Flutter系列博文鏈接 ↓:

工具安裝:

Flutter基礎(chǔ)篇:

Flutter進(jìn)階篇:

Dart語(yǔ)法系列博文鏈接 ↓:

Dart語(yǔ)法基礎(chǔ)篇:

Dart語(yǔ)法進(jìn)階篇:


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

上一篇主要講了Dart的類與函數(shù),由于內(nèi)容有太多,我就把剩下的內(nèi)容分開寫一篇文章。
這一篇我們講Dart的泛型、異步、庫(kù)等有關(guān)詳解,內(nèi)容較多,希望大家可以耐心看完。我也是花了很長(zhǎng)時(shí)間研究的。喜歡的就點(diǎn)個(gè)贊,打個(gè)賞吧。
感謝大家支持。


九、泛型(Generics)

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

(一)為什么使用泛型?

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

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

如果您希望列表只包含字符串,則可以將其聲明為L(zhǎng)ist<String>(將其讀作“字符串列表”)。這樣一來(lái),工具可以檢測(cè)到將非字符串分配給列表可能是一個(gè)錯(cuò)誤。
例子:

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

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

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

您發(fā)現(xiàn)需要此接口針對(duì)字符串的做一個(gè)緩存,因此您需要?jiǎng)?chuàng)建另一個(gè)接口:

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

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

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

(二)使用集合文字

list和map文字可以參數(shù)化。參數(shù)化文字就像你已經(jīng)看到的文字一樣,除了你在開始括號(hào)之前添加 <type>(對(duì)于list)或 <keyType, valueType>(對(duì)于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ù)時(shí)指定一個(gè)或多個(gè)類型,請(qǐng)將類型放在類名稱后面的尖括號(hào)<...>中。例如:

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

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

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

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

Dart的泛型類型是具體的。也就說(shuō),它們?cè)谶\(yùn)行時(shí)會(huì)會(huì)攜帶類型信息。示例如下:(相反,Java中的泛型使用擦除,這意味著在運(yùn)行時(shí)刪除泛型類型參數(shù)。在Java中,您可以測(cè)試對(duì)象是否為L(zhǎng)ist,但您無(wú)法測(cè)試它是否是List<String>。)

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

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

實(shí)現(xiàn)泛型類型時(shí),您可能希望限制其參數(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類型會(huì)導(dǎo)致錯(cuò)誤。
例如:var foo = Foo<Object>;

(六)使用泛型方法

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

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

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

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

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

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

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

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

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

2.聲明一個(gè)本地泛型函數(shù)本身

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

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

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

十、庫(kù)和可見(jiàn)性

該import和library指令可以幫助您創(chuàng)建一個(gè)模塊化的,可共享的代碼庫(kù)。庫(kù)不僅提供API,還是隱私單元(以下劃線(_)開頭的標(biāo)識(shí)符僅在庫(kù)內(nèi)可見(jiàn))。每個(gè)Dart應(yīng)用程序都是一個(gè)庫(kù),即使它不使用library指令。可以使用包來(lái)分發(fā)庫(kù)。

(一)使用庫(kù)

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

(二)指定庫(kù)前綴

如果導(dǎo)入兩個(gè)具有沖突標(biāo)識(shí)符的庫(kù),則可以為一個(gè)或兩個(gè)庫(kù)指定前綴。例如,如果test2.dart和test3.dart都有一個(gè)hello()函數(shù),那么直接導(dǎo)入這兩個(gè)文件會(huì)有沖突,這種情況下我們可以使用as關(guān)鍵字給庫(kù)指定一個(gè)前綴:

test2.dart代碼如下:

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

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

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

導(dǎo)入庫(kù)也可以使用相對(duì)路徑。例如:lib/demo1/a.dart, lib/demo2/b.dart這兩個(gè)文件。現(xiàn)在b.dart這個(gè)文件需要引用a.dart,可以使用import '../demo1/a.dart'導(dǎo)入。

(三)僅導(dǎo)入庫(kù)的一部分

如果只想使用庫(kù)的一部分,則可以有選擇地導(dǎo)入庫(kù),可以使用show或者hide關(guān)鍵字。例如:show表示僅導(dǎo)入當(dāng)前庫(kù),hide表示除了當(dāng)前庫(kù)之外全部導(dǎo)入。

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

(四)懶加載一個(gè)庫(kù)

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

  • 1).減少應(yīng)用程序的初始啟動(dòng)時(shí)間。
  • 2).例如,執(zhí)行A/B測(cè)試 - 嘗試算法的替代實(shí)現(xiàn)。
  • 3).加載很少使用的功能,例如可選的屏幕和對(duì)話框。
    要延遲加載庫(kù),必須先使用deferred as它導(dǎo)入一個(gè)庫(kù)。當(dāng)我們import一個(gè)庫(kù)的時(shí)候,如果使用了as 不能同時(shí)使用deferred as
    例如:
// import 'libs/mylib.dart'; // 不能同時(shí)使用
import 'libs/mylib.dart' deferred as tests;

當(dāng)您需要庫(kù)時(shí),使用庫(kù)的標(biāo)識(shí)符調(diào)用loadLibrary()。
例如(注意導(dǎo)包:import 'dart:async';):

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

在上述的代碼中,await關(guān)鍵字暫停執(zhí)行,直到庫(kù)被加載。
您可以在一個(gè)庫(kù)上調(diào)用loadLibrary()多次,而不會(huì)出現(xiàn)問(wèn)題。該庫(kù)只加載一次。

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

  • 1).延遲庫(kù)的常量不是導(dǎo)入文件中的常量。請(qǐng)記住,在加載延遲庫(kù)之前,這些常量不存在。
  • 2).您不能在導(dǎo)入文件中使用延遲庫(kù)中的類型。相反,請(qǐng)考慮將接口類型移動(dòng)到由延遲庫(kù)和導(dǎo)入文件導(dǎo)入的*庫(kù)。
  • 3).Dart隱式插入loadLibrary()到你使用deferred as namespace定義的命名空間。loadLibrary()函數(shù)返回Future。

(五)庫(kù)的拆分

【說(shuō)明】dart官網(wǎng)不推薦使用part ,這個(gè)僅作為了解。
使用part指令,可以將庫(kù)拆分為多個(gè)Dart文件。part of表示隸屬于某個(gè)庫(kù)的一部分。
注意事項(xiàng):

  • 1.不能同時(shí)使用library和part of,它們都用于指定屬于庫(kù)的內(nèi)容。
// library testlib2; 這個(gè)不能和part of同時(shí)使用 會(huì)報(bào)錯(cuò)
// part of 表示這個(gè)庫(kù)是testlib庫(kù)的一部分
part of testlib1;
    1. B庫(kù)是A庫(kù)的一部分,在B庫(kù)里面聲明:part of A庫(kù)名稱
      例如:在testlib2.dart里面聲明 part of testlib1; 表示testlib2這個(gè)庫(kù)是testlib庫(kù)的yi部分。
    1. 如果B庫(kù)聲明A庫(kù)的一部分,同時(shí)A庫(kù)也想聲明它的一部分是B庫(kù),正確寫法:B庫(kù)聲明part of A庫(kù)名稱,然后A庫(kù)聲明part 'B庫(kù)的路徑' , 同時(shí),如果B庫(kù)沒(méi)有聲明,那么在A庫(kù)里面使用part指令會(huì)報(bào)錯(cuò)。
      testlib1.dart內(nèi)容:
// 第1個(gè)庫(kù):
library testlib1;
// 可以不寫
part 'testlib2.dart';
void run() {
  print('testlib1庫(kù) : run()函數(shù)');
}

testlib2.dart內(nèi)容:

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

(六)庫(kù)的自動(dòng)導(dǎo)入

在A庫(kù)中使用export關(guān)鍵字引入B庫(kù),當(dāng)我們使用A庫(kù)的時(shí)候,會(huì)自動(dòng)引入B庫(kù),也就是說(shuō)我們導(dǎo)入了A庫(kù),就可以使用B庫(kù)了。
mylib.dart內(nèi)容為:

// 這是一個(gè)庫(kù) 命名為mylib
library mylib;
// 希望使用mylib的時(shí)候 自動(dòng)使用otherlib.dart  可以使用export關(guān)鍵字引入其他庫(kù)
export 'otherlib.dart';
// 導(dǎo)入otherlib2.dart
export 'otherlib2.dart';

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

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

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

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

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

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

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

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


十一、異步支持

Dart庫(kù)中包含許多返回Future或Stream對(duì)象的函數(shù)。這些函數(shù)是異步的:它們?cè)谠O(shè)置可能耗時(shí)的操作(例如I / O)后返回,而不等待該操作完成。

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

asyncawait關(guān)鍵字支持異步編程,讓你寫異步代碼看起來(lái)類似于同步代碼。

(一)處理Future

當(dāng)您需要完成Future的結(jié)果時(shí),您有兩個(gè)選擇:

  • 1).使用async和await。
  • 2).使用Future API,如 庫(kù)瀏覽 中所述。

(二)使用async和await

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

要使用async,代碼必須在async函數(shù)中(標(biāo)記為async的函數(shù))。
例如:

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

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

使用try,catch,finally在使用await的代碼中處理錯(cuò)誤和清理代碼。

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

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

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

在await表達(dá)式中,表達(dá)式的值通常是Future; 如果不是,那么該值將自動(dòng)包含在Future中。 這個(gè)Future對(duì)象表示返回一個(gè)對(duì)象的promise。 await表達(dá)式的值是返回的對(duì)象。 await表達(dá)式使執(zhí)行暫停,直到該對(duì)象可用。

如果在使用await時(shí)遇到編譯時(shí)錯(cuò)誤,請(qǐng)確保await在async函數(shù)中。
例如,要在應(yīng)用程序的main()函數(shù)中使用await,main()方法必須標(biāo)記為async:以下是一個(gè)完整的示例代碼:

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 '版本號(hào):v1.0';
}

結(jié)果:

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

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

方法被async修飾的函數(shù)是異步函數(shù)。給一個(gè)函數(shù)添加async關(guān)鍵字,使得返回值是一個(gè)Future。

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

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

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

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

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

如果您的函數(shù)沒(méi)有返回有用的值,請(qǐng)?jiān)O(shè)置其返回類型Future<void>
例如:

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

(四)處理Stream

當(dāng)您需要完成Future的結(jié)果時(shí),您有兩個(gè)選擇:

  • 1).使用async和異步for循環(huán)(await for)。
    注意:在使用await for之前,請(qǐng)確保它使代碼更清晰,并且您確實(shí)希望等待所有Stream的結(jié)果。 例如,通常情況,不應(yīng)該使用await for UI事件偵聽(tīng)器,因?yàn)閁I框架會(huì)發(fā)送無(wú)窮無(wú)盡的事件流(streams of events)。
  • 2).使用Stream API(主要是IO操作。)

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

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流進(jìn)行文件讀取
      Stream<List<int>> inputStream = config.openRead();
      var lines = inputStream
        // 設(shè)置編碼格式為utf-8
        .transform(utf8.decoder)
        .transform(LineSplitter());
      try {
          await for (var line in lines) {
              print('從Stream中獲取到的內(nèi)容是: ${line} \r文本內(nèi)容長(zhǎng)度為:'+ '${line.length}\r=======');
          }
        print('文件現(xiàn)在沒(méi)有關(guān)閉。。。');
      } catch (e) {
        print(e);
      }
}

表達(dá)式的值必須有Stream類型,執(zhí)行過(guò)程如下:

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

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

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

有關(guān)異步編程的更多信息,請(qǐng)查看庫(kù)瀏覽的 Dart庫(kù)之旅 --- dart:async 部分,另請(qǐng)參閱文章 Dart語(yǔ)言異步支持:階段2(該頁(yè)面可能過(guò)期了) 和 Dart語(yǔ)言規(guī)范。


十二、Isolates

大多數(shù)計(jì)算機(jī),甚至在移動(dòng)平臺(tái)上,都有多核CPU。為了利用所有這些核心,開發(fā)人員傳統(tǒng)上使用并發(fā)運(yùn)行的共享內(nèi)存線程。但是,共享狀態(tài)并發(fā)容易出錯(cuò),并且可能導(dǎo)致代碼復(fù)雜化。
所有Dart代碼都在隔離區(qū)內(nèi)運(yùn)行,而不是線程。每個(gè)隔離區(qū)都有自己的內(nèi)存堆,確保不會(huì)從任何其他隔離區(qū)訪問(wèn)隔離區(qū)的狀態(tài)。

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

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

使用isolate 需要先導(dǎo)入包:import 'dart:isolate';

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

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

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

/// 期望通過(guò)[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)

當(dāng)您需要懶惰地生成一系列值時(shí),請(qǐng)考慮使用生成器函數(shù)。Dart支持兩種生成器功能。

(一)同步生成器,返回一個(gè)Iterable對(duì)象。

要實(shí)現(xiàn)同步生成器函數(shù),請(qǐng)將函數(shù)體標(biāo)記為sync*,并使用yield語(yǔ)句來(lái)傳遞值。

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

如果您的生成器是遞歸的,您可以使用yield*以下方法來(lái)提高其性能:

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

(二)異步生成器,返回一個(gè)Stream對(duì)象。

要實(shí)現(xiàn)異步生成器函數(shù),請(qǐng)將函數(shù)體標(biāo)記為async*,并使用yield語(yǔ)句來(lái)傳遞值。

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

十四、類型定義

在Dart中,函數(shù)是對(duì)象,就像字符串一樣,數(shù)字是對(duì)象。一個(gè)類型定義,或功能型的別名,給出了一個(gè)函數(shù)類型聲明字段時(shí),您可以使用和返回類型的名稱。當(dāng)函數(shù)類型分配給變量時(shí),typedef會(huì)保留類型信息。

以下代碼,它不使用typedef:我們可以看到compare是一個(gè)函數(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是一個(gè)函數(shù),但它是哪一種類型的函數(shù)?
  assert(coll.compare is Function);
}

接下來(lái)使用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ù)類型。

因?yàn)閠ypedef只是別名,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ù)提供有關(guān)代碼的其他信息。元數(shù)據(jù)注解以字符開頭@,后跟對(duì)編譯時(shí)常量(如deprecated)的引用或?qū)ΤA繕?gòu)造函數(shù)的調(diào)用。
元數(shù)據(jù)可以出現(xiàn)在庫(kù),類,typedef,類型參數(shù),構(gòu)造函數(shù),工廠,函數(shù),字段,參數(shù)或變量聲明之前以及導(dǎo)入或?qū)С鲋噶钪啊D梢允褂梅瓷湓谶\(yùn)行時(shí)檢索元數(shù)據(jù)。
所有Dart代碼都有兩個(gè)注解:@deprecated@override
以下是使用@deprecated 注解的示例:

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

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

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

這是一個(gè)定義帶有兩個(gè)參數(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)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。