版權(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基礎篇:
- 谷歌Flutter1.0正式版發(fā)布
- Flutter基礎篇(1)-- 跨平臺開發(fā)框架和工具集錦
- Flutter基礎篇(2)-- 老司機用一篇博客帶你快速熟悉Dart語法
- Flutter基礎篇(3)-- Flutter基礎全面詳解
- Flutter基礎篇(4)-- Flutter填坑全面總結(jié)
- Flutter基礎篇(5)-- Flutter代碼模板茉帅,解放雙手叨叙,提高開發(fā)效率必備
- Flutter基礎篇(6)-- 水平和垂直布局詳解
- Flutter基礎篇(7)-- Flutter更新錯誤全面解決方案(圖文+視頻講解)
- Flutter基礎篇(8)-- Flutter for Web詳細介紹
- Flutter基礎篇(9)-- 手把手教你用Flutter實現(xiàn)Web頁面編寫
- Flutter1.9升級體驗總結(jié)(Flutter Web 1.9最新版本填坑指南)
Flutter進階篇:
- Flutter進階篇(1)-- 手把手帶你快速上手調(diào)試Flutter項目
- Flutter進階篇(2)-- Flutter路由詳解
- Flutter進階篇(3)-- Flutter 的手勢(GestureDetector)分析詳解
- Flutter進階篇(4)-- Flutter的Future異步詳解
- Flutter進階篇(5)-- 使用Flutter創(chuàng)建插件詳解并發(fā)布到Pub庫
- Flutter進階篇(6)-- PageStorageKey锭弊、PageStorageBucket和PageStorage使用詳解
- Flutter進階篇(7)-- Flutter路由輕量級框架FRouter
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;
- B庫是A庫的一部分,在B庫里面聲明:part of A庫名稱
例如:在testlib2.dart里面聲明part of testlib1
; 表示testlib2這個庫是testlib庫的yi部分吧恃。
- B庫是A庫的一部分,在B庫里面聲明:part of A庫名稱
- 如果B庫聲明A庫的一部分虾啦,同時A庫也想聲明它的一部分是B庫,正確寫法:B庫聲明part of A庫名稱,然后A庫聲明part 'B庫的路徑' , 同時傲醉,如果B庫沒有聲明蝇闭,那么在A庫里面使用part指令會報錯。
testlib1.dart內(nèi)容:
- 如果B庫聲明A庫的一部分虾啦,同時A庫也想聲明它的一部分是B庫,正確寫法:B庫聲明part of A庫名稱,然后A庫聲明part 'B庫的路徑' , 同時傲醉,如果B庫沒有聲明蝇闭,那么在A庫里面使用part指令會報錯。
// 第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ù)');
}
- 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
async
和await
關鍵字支持異步編程茫因,讓你寫異步代碼看起來類似于同步代碼。
(一)處理Future
當您需要完成Future的結(jié)果時越除,您有兩個選擇:
- 1).使用async和await节腐。
- 2).使用Future API,如 庫瀏覽 中所述摘盆。
(二)使用async和await
使用async
和await
異步的代碼,但它看起來很像同步代碼饱苟。例如孩擂,這里有一些代碼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');
}