const與final
- 區(qū)別一:final要求變量只能初始化一次,并不要求賦的值一定是編譯時(shí)常量。而const要求在聲明時(shí)初始化,并且賦值必需為編譯時(shí)常量。
- 區(qū)別二:final是惰性初始化,即在運(yùn)行時(shí)第一次使用前才初始化。而 const 是在編譯時(shí)就確定值了。
//這里 const 和 final 沒有區(qū)別,因?yàn)樽兞?a 被立即賦值為一個(gè)數(shù)字常量
void test1() {
var a1 = 1;
const a2 = 1;
final a3 = 1;
int a4 = 1;
const int a5 = 1;
final int a6 = 1;
}
什么是編譯時(shí)常量
指的是:字面量(如數(shù)字、bool、字符串、List的字面量形式)、其它常量或者常量的算術(shù)運(yùn)算,也可以是這些的組合形式,簡(jiǎn)單地說(shuō)常量就是可以在編譯時(shí)確定的值。如下:
//const可以如下定義
void test2() {
const a = 8;
const b = false;
const c = a;
const d = 5 * 3;
const e = a * d + 2;
}
而其它形式,比如實(shí)例化一個(gè)新的對(duì)象,一個(gè)函數(shù)調(diào)用的返回值就不是編譯時(shí)常量了,它們?cè)谶\(yùn)行時(shí)才能獲得結(jié)果。
void test3() {
final x1 = new DateTime.now(); //ok
const x2 = new DateTime.now();//error
}
final 實(shí)例成員
//聲明時(shí)直接初始化
class X1 {
final a = 0;
}
//或構(gòu)造方法中初始化
class X2 {
final a;
X2(this.a){
}
}
//或初始化列表中初始化
class X3 {
final a;
X3(a): this.a = a{
}
}
const 實(shí)例成員
class X {
//只能聲明時(shí)直接初始化
static const a = 0;//必須是static的
X(){
}
}
常量對(duì)象和常量構(gòu)造函數(shù)
前面說(shuō)的編譯時(shí)常量還包括常量對(duì)象,也就是通過(guò) const 構(gòu)造函數(shù)創(chuàng)建的對(duì)象。
- 所有實(shí)例成員都是 final 或 const 實(shí)例成員,那么該類所創(chuàng)建的對(duì)象的狀態(tài)就是不可變的。
- 定義 const 構(gòu)造函數(shù),const 構(gòu)造函數(shù)所創(chuàng)建的對(duì)象就是常量對(duì)象。
- 用 const 代替 new 來(lái)調(diào)用構(gòu)造函數(shù)。
- 可以用 new 調(diào)用 const 構(gòu)造函數(shù),但那樣就不能用 const 聲明該變量了。
- const 構(gòu)造函數(shù)也不能有函數(shù)體。
- 常量對(duì)象還有一個(gè)特點(diǎn),相同的常量對(duì)象始終只有一個(gè)。
class Constant {
static const a = 1;
final b;
const Constant(this.b); //不能有函數(shù)體
static const m = const Constant(3);
}
main(){
const x1 = const Constant(3);// ok
const x2 = new Constant(3);// error
final x3 = const Constant(3);// ok
final x4 = new Constant(5);// ok
assert(x1 == x3);
assert(x1 != x4);
}
區(qū)別三:const 可以修飾變量,也可以修飾值,而 final 只用來(lái)修飾變量。
void test4(){
const list1 = [1, 2, 3]; // error
const list2 = const [1, 2, 3];
const list3 = const [new DateTime.now(), 2, 3]; // error, 因?yàn)閚ew DateTime.now()不是const
const list4 = const [const Constant(3), 2, 3];
var x1 = 5;
const list5 = const[x1]; //error,x1不是const
const x2 = 5;
const list6 = const[x2];
final list7 = [1, 2, 3];
final list8 = const [1, 2, 3];
final list9 = const [new DateTime.now(), 2, 3];// error, 因?yàn)閚ew DateTime.now()不是const
}
const 修飾值的時(shí)候,要求值必需是常量或由常量組成。var、final等在左邊定義變量時(shí),并不關(guān)心右邊是不是常量。但如果右邊用了const,那么不管左邊是什么要求,右邊都必需是常量。
異步
Async和await
Future getName1() async {
await getStr1();
print('getName1');
}
getStr1() {
print('getStr1');
}
getName2() {
print('getName2');
}
getName3() {
print('getName3');
}
goAsync() {
getName1();
getName2();
getName3();
}
//輸出結(jié)果
getStr1
getName2
getName3
getName1
- return的類型為T,那么函數(shù)的返回類型應(yīng)該為Future<T>,或T的父類,否則會(huì)產(chǎn)生靜態(tài)警告。
- 如果函數(shù)中return的類型是Future<T>,那么函數(shù)的返回類型同樣為Future<T>,而不是Future<Future<T>>。
- await表達(dá)式可以使用多次,但只能在async標(biāo)記的函數(shù)中使用。
Future
Future表示在將來(lái)某時(shí)獲取一個(gè)值的方式。當(dāng)一個(gè)返回Future的函數(shù)被調(diào)用的時(shí)候,做了兩件事情:
- 函數(shù)把自己放入隊(duì)列和返回一個(gè)未完成的Future對(duì)象
- 之后當(dāng)值可用時(shí),F(xiàn)uture帶著值變成完成狀態(tài)。
//1.使用then按指定順序
getName2().then((_) => getName1()).then((_) => getName3());
//2.使用whenComplete()按指定順序
getName2().whenComplete(() {
getName1().whenComplete(() {
getName3();
});
});
//3.使用wait,一并返回完成值
Future.wait([getName2(), getName1(), getName3()])
.then((List re) {
re.forEach((i) => print(i));
});
Future與異常
//返回都是Future可以用鏈?zhǔn)浇Y(jié)構(gòu)
void goThrow() {
new Future(() => print('start'))
.then((_) => new Future.error("xxxxxx"))
.whenComplete(() => print("run"))
.then((_) => print("don't"))
.catchError((e) => print(e));
}
//混合同步類型和異步類型的異常
main() {
fun3().catchError((e){
print('e = $e');
});
}
fun1() {
throw 'fun1 is error';
}
fun2() {
throw 'fun2 is error';
}
//方法1:
//Future fun3(){
// return new Future.sync((){
// fun1();
// return new Future(() {
// fun2();
// });
// });
//}
//方法2:
Future fun3() async{
fun1();
return new Future(() {
fun2();
});
}
事件隊(duì)列
- Dart應(yīng)用程序僅有一個(gè)消息循環(huán),以及兩個(gè)隊(duì)列:event事件隊(duì)列和microtask微任務(wù)隊(duì)列。
- 事件隊(duì)列包含所有的外部事件,如:I/O、鼠標(biāo)事件、定時(shí)器、Isolate之間的消息等等。
當(dāng)main函數(shù)退出后,消息循環(huán)開始工作,首先FIFO的方式執(zhí)行所有微任務(wù)。接著,從事件隊(duì)列中提取消息并一條條處理,然后再執(zhí)行所有的微任務(wù),以此循環(huán),直到所有隊(duì)列為空。
如何調(diào)度任務(wù)
dart:async包中提供的如下API:
- Future類,可添加一個(gè)事件到事件隊(duì)列的末尾;
- 頂層函數(shù) scheduleMicrotask(),可添加一個(gè)任務(wù)到微任務(wù)隊(duì)列的末尾。
Future幾點(diǎn)注意事項(xiàng):
- 當(dāng)Future完成計(jì)算后,then()注冊(cè)的回調(diào)函數(shù)會(huì)立即執(zhí)行。需注意的是,then()注冊(cè)的函數(shù)并不會(huì)添加到事件隊(duì)列中,回調(diào)函數(shù)只是在事件循環(huán)中任務(wù)完成后被調(diào)用。
- 如果Future在then()被調(diào)用之前已經(jīng)完成計(jì)算,那么任務(wù)會(huì)被添加到微任務(wù)隊(duì)列中,并且該任務(wù)會(huì)執(zhí)行then()中注冊(cè)的回調(diào)函數(shù)。
- Future()和Future.delayed()構(gòu)造函數(shù)并不會(huì)立即完成計(jì)算。
- Future.value()構(gòu)造函數(shù)在微任務(wù)中完成計(jì)算,其他類似第2條。
- Future.sync()構(gòu)造函數(shù)會(huì)立即執(zhí)行函數(shù),并在微任務(wù)中完成計(jì)算,其他類似第2條。
//demo1
import 'dart:async';
main() async {
Future f1 = new Future(() => null);
Future f2 = new Future(() => null);
Future f3 = new Future(() => null);
f3.then((_) => print("1"));
f2.then((_) {
print("2");
new Future(() => print("3"));
f1.then((_) {
print("4");
});
});
}
//運(yùn)行結(jié)果
2
4
1
3
//demo2
import 'dart:async';
main() {
print('1');
scheduleMicrotask(() => print('s1'));
new Future.delayed(new Duration(seconds: 1), () => print('d1'));
new Future(() => print('f1')).then((_) {
print('f2');
scheduleMicrotask(() => print('s3'));
}).then((_) => print('f3'));
new Future(() => print('f4'));
scheduleMicrotask(() => print('s2'));
print('2');
}
//打印結(jié)果:
1
2
s1
s2
f1
f2
f3
s3
f4
d1
注意點(diǎn):
- 盡量使用事件隊(duì)列,微任務(wù)要盡量簡(jiǎn)單,否則會(huì)引起鼠標(biāo)無(wú)反應(yīng)等。
- 為使應(yīng)用程序保持響應(yīng),避免在事件循環(huán)中添加計(jì)算密集型代碼
- 執(zhí)行計(jì)算密集型代碼的時(shí)候,另創(chuàng)建Isolate
生成器
生成器有兩種類型:同步生成器和異步生成器。
同步生成器:sync*
Iterable getNum(n) sync* {
print("Begin");
int k = 0;
while (k < n) {
//moveNext會(huì)返回true給調(diào)用者。
//函數(shù)會(huì)在下次調(diào)用moveNext的時(shí)候恢復(fù)執(zhí)行。
yield k++;
}
print("End");
}
goIterable() {
//調(diào)用getNun立即返回Iterable
var it = getNum(3).iterator;
//調(diào)用moveNext方法時(shí)getNum才開始執(zhí)行
while(it.moveNext()) {
print(it.current);
}
print('over');
}
//打印結(jié)果
Begin
0
1
2
End
over
異步生成器:async*
Stream getNum(n) async* {
print("Begin");
int k = 0;
while (k < n) {
//不用暫停,數(shù)據(jù)流通過(guò)StreamSubscription進(jìn)行控制
yield k++;
}
print("End");
}
goStream() {
//調(diào)用getNum立即返回Stream,只有執(zhí)行了listen,函數(shù)才會(huì)開始執(zhí)行
getNum(3).listen((v) {
print(v);
});
print('over');
}
//打印結(jié)果
over
Begin
0
1
2
End