一、Dart語言簡介
百度(玄語):
..
(級聯運算符)和
?.
(條件成員訪問運算符)以及
??
(判空賦值運算符)。在 Dart 中其實看到的不僅有 Java 和 JavaScript 的影子,它還具有其它編程語言中的身影,如命名參數在 Objective-C 和 Swift 中早就很普遍。
二、變量聲明
1、var
1、類似於 JavaScript 中的var
2、不同是 Dart 中 var 變量一旦賦值,類型便會確定,則不能再改變
2、dynamic 和 Object
1、Object
是 Dart 所有對象的根基類,所以任何類型的數據都可以賦值給Object
聲明的對象
2、dynamic
與Object
聲明的變量都可以賦值任意對象,且后期可以改變賦值的類型
3、dynamic
與Object
不同的是dynamic
聲明的對象編譯器會提供所有可能的組合,而Object
聲明的對象只能使用 Object
的屬性與方法, 否則編譯器會報錯
3、final和const
1、從未打算更改一個變量,那么使用 final
或 const
2、const
變量是一個編譯時常量(編譯時直接替換為常量值),final
變量在第一次使用時被初始化。被final
或者const
修飾的變量,變量類型可以省略
//可以省略String這個類型聲明
final str = "hi world";
//final String str = "hi world";
const str1 = "hi world";
//const String str1 = "hi world";
4、空安全(null-safety)
1、Dart 中一切都是對象,這意味着如果我們定義一個數字,在初始化它之前如果我們使用了它,假如沒有某種檢查機制,則不會報錯,如:
test() {
int i; .//未初始化
print(i*8);
}
2、在 Dart 引入空安全之前,上面代碼在執行前不會報錯,但會觸發一個運行時錯誤,原因是 i 的值為 null 。但現在有了空安全,則定義變量時我們可以指定變量是可空還是不可空
int i = 8; //默認為不可空,必須在定義時初始化。
int? j; // 定義為可空類型,對於可空變量,我們在使用前必須判空。
// 如果我們預期變量不能為空,但在定義時不能確定其初始值,則可以加上late關鍵字,
// 表示會稍后初始化,但是在正式使用它之前必須得保證初始化過了,否則會報錯
late int k;
k=9;
3、如果一個變量我們定義為可空類型,在某些情況下即使我們給它賦值過了,但是預處理器仍然有可能識別不出,這時我們就要顯式(通過在變量后面加一個”!“符號)告訴預處理器它已經不是null了
三、函數
1、函數聲明:如果沒有顯式聲明返回值類型時會默認當做dynamic
處理,注意,函數返回值沒有類型
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
typedef bool CALLBACK();
//不指定返回類型,此時默認為dynamic,不是bool
isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void test(CALLBACK cb){
print(cb());
}
//報錯,isNoble不是bool類型
test(isNoble);
2、對於只包含一個表達式的函數,可以使用簡寫語法
bool isNoble (int atomicNumber)=> true ;
3、函數作為變量
var say = (str){
print(str);
};
say("hi world");
4、函數作為參數傳遞
void execute(var callback) {
callback();
}
execute(() => print("xxx"))
5、可選的位置參數
//包裝一組函數參數,用[]標記為可選的位置參數,並放在參數列表的最后面:
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
//下面是一個不帶可選參數調用這個函數的例子:
say('Bob', 'Howdy'); //結果是: Bob says Howdy
//下面是用第三個參數調用這個函數的例子:
say('Bob', 'Howdy', 'smoke signal'); //結果是:Bob says Howdy with a smoke signal
6、可選的命名參數
定義函數時,使用{param1, param2, …},放在參數列表的最后面,用於指定命名參數。例如:
//設置[bold]和[hidden]標志
void enableFlags({bool bold, bool hidden}) {
// ...
}
調用函數時,可以使用指定命名參數。例如:paramName: value
enableFlags(bold: true, hidden: false);
四、mixin
Dart 是不支持多繼承的,但是它支持 mixin,簡單來講 mixin 可以 “組合” 多個類,我們通過一個例子來理解。
定義一個 Person 類,實現吃飯、說話、走路和寫代碼功能,同時定義一個 Dog 類,實現吃飯、和走路功能:我們定義了幾個 mixin,然后通過 with 關鍵字將它們組合成不同的類。有一點需要注意:如果多個mixin 中有同名方法,with 時,會默認使用最后面的 mixin 的,mixin 方法中可以通過 super 關鍵字調用之前 mixin 或類中的方法。
class Person {
say() {
print('say');
}
}
mixin Eat {
eat() {
print('eat');
}
}
mixin Walk {
walk() {
print('walk');
}
}
mixin Code {
code() {
print('key');
}
}
class Dog with Eat, Walk{}
class Man extends Person with Eat, Walk, Code{}
五、異步支持
Dart類庫有非常多的返回Future
或者Stream
對象的函數。 這些函數被稱為異步函數:它們只會在設置好一些耗時操作之后返回
async
和await
關鍵詞支持了異步編程,允許寫出和同步代碼很像的異步代碼
1、Future
Future
與JavaScript中的Promise
非常相似,表示一個異步操作的最終完成(或失敗)及其結果值的表示。簡單來說,它就是用於處理異步操作的,異步處理成功了就執行成功的操作,異步處理失敗了就捕獲錯誤或者停止后續操作。一個Future只會對應一個結果,要么成功,要么失敗。
由於本身功能較多,這里我們只介紹其常用的API及特性。還有,請記住,Future
其他:待補充
六、Stream
Stream
也是用於接收異步事件數據,和 Future
不同的是,它可以接收多個異步操作的結果(成功或失敗)。 也就是說,在執行異步任務時,可以通過多次觸發成功或失敗事件來傳遞結果數據或錯誤異常。 Stream
常用於會多次讀取數據的異步任務場景,如網絡內容下載、文件讀寫等。舉個例子:
Stream.fromFutures([
// 1秒后返回結果
Future.delayed(Duration(seconds: 1), () {
return "hello 1";
}),
// 拋出一個異常
Future.delayed(Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回結果
Future.delayed(Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){
});
輸出:
I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3
七、 Dart和Java及JavaScript對比
1、Dart vs Java
客觀的來講,Dart 在語法層面確實比 Java 更有表現力;在 VM 層面,Dart VM 在內存回收和吞吐量都進行了反復的優化,但具體的性能對比,筆者沒有找到相關測試數據,但在筆者看來,只要 Dart 語言能流行,VM 的性能就不用擔心,畢竟 Google 在 Go(沒用VM但有GC)、JavaScript(v8)、Dalvik( Android 上的 Java VM )上已經有了很多技術積淀。值得注意的是 Dart 在 Flutter 中已經可以將 GC 做到 10ms 以內,所以 Dart 和 Java 相比,決勝因素並不會是在性能方面。而在語法層面,Dart 要比 Java 更有表現力,最重要的是 Dart 對函數式編程支持要遠強於 Java(目前只停留在 Lambda 表達式),而 Dart 目前真正的不足是生態,但筆者相信,隨着 Flutter 的逐漸火熱,會回過頭來反推 Dart 生態加速發展,對於 Dart 來說,現在需要的是時間。
2、Dart vs JavaScript
JavaScript 的弱類型一直被抓短,所以 TypeScript 甚至是 Facebook 的 Flow 才有市場。就筆者使用過的腳本語言中(筆者曾使用過 Python、PHP),JavaScript 無疑是動態化支持最好的腳本語言,比如在 JavaScript 中,可以給任何對象在任何時候動態擴展屬性,對於精通 JavaScript 的高手來說,這無疑是一把利劍。但是,任何事物都有兩面性,JavaScript 強大的動態化特性也是把雙刃劍,你可經常聽到另一個聲音,認為 JavaScript 的這種動態性糟糕透了,太過靈活反而導致代碼很難預期,無法限制不被期望的修改。畢竟有些人總是對自己或別人寫的代碼不放心,他們希望能夠讓代碼變得可控,並期望有一套靜態類型檢查系統來幫助自己減少錯誤。正因如此,在 Flutter中,Dart 幾乎放棄了腳本語言動態化的特性,如不支持反射、也不支持動態創建函數等。並且 Dart 從 2.0 開始強制開啟了類型檢查(Strong Mode),原先的檢查模式(checked mode)和可選類型(optional type)將淡出,所以在類型安全這個層面來說,Dart 和 TypeScript、CoffeeScript 是差不多的,所以單從動態性來看,Dart 並不具備什么明顯優勢,但綜合起來看,Dart 既能進行服務端腳本、APP 開發、Web 開發,這就有優勢了!