工作上的需要,被迫上線學習Flutter,看了下文件和線上的專欄,人老了,怕容易忘記,記錄下筆記,如果有錯誤的地方,煩請糾正。
一、Dart簡介
Dart是Google在2011年10月正式釋出的程式語言,起初的定位是執行在瀏覽器的指令碼語言。是Google大神由於不滿JavaScript開發的程式後期難維護問題,而新研發的一種物件導向程式語言。然而nodejs的出現,JavaScript很快覆蓋了全棧,很多手機應用和桌面應用也成為了JavaScript的宿主容器。這使Dart始終不溫不火,這麼多年來內建Dart VM的瀏覽器廠家也只有Google自己的產品Chrome(現在好像已經移除)。
很多人都有疑問,為什麼JavaScript那麼火,而Dart的開發者那麼稀缺,Flutter會選擇Dart作為基礎語言去研發呢?這不會提高開發者的介入成本,不利於推廣嗎?個人感覺應該以下幾個原因:
- Dart是Google自主研發產品,可以避免很多類似Oracle和Android的爭議問題。
- 自主研發語言,可以靈活迭代,為Flutter架構的形成做最有力的支撐。
- Dart 尋求轉型,想彎道超車進入移動開發的領域
那麼Google選擇了用Dart語言開發Flutter框架,除了我們分析的客觀原因外,Dart本身有哪些特性是值得Flutter去選擇的?
二、Dart特性
- Dart是宣告式佈局語言,易於閱讀和視覺化,可以不通過視覺化構建器,通過熱過載直接真機除錯。
- 同時支援JIT(即時編譯,JavaScript,Python)和AOT(執行前編譯,C,C++) Dart在開發階段,使用了JIT編譯,這可以提高它的研發效率,降低研發週期。Flutter最受歡迎的熱過載,正是因為這一特性。而釋出的時候使用AOT,就不用像RN那樣,在JavaScript和原生中建立低效的方法呼叫對映,因此,Dart具有執行速度快,執行效能好的特點。
- Drat是單執行緒模型,不需要像多執行緒那樣處理資源共享和資料同步問題,這也就意味著一個函式執行,就將執行到函式結束為止,期間不會被其他Dart程式碼所打斷。Dart的Isolate(隔離區)不會共享記憶體,幾個單獨的worker之間,通過事件迴圈在事件佇列中進行通訊(類似Node)。
三、Dart基礎語法
Dart的執行依賴於Dart VM,大家可以通過安裝Dart SDK,來體驗Dart。安裝過程以MacOS為例子,可以通過brew安裝
brew tap dart-lang/dart
brew install dart
複製程式碼
接著在VSCode安裝Dart外掛和code runner外掛即可在vscode中體驗Dart程式設計。
跟很多程式語言一樣,Dart同樣以main函式作為執行入口
void main() {
print('hello world');
}
複製程式碼
Dart變數
Dart可以通過var關鍵字建立變數,當使用var時,型別是通過編譯器推斷決定.
var name = 'tony';
print(name is String); // true
複製程式碼
在預設情況下,未初始化的變數值為null,所以我們不需要擔心無法判斷一個傳遞過來的變數是undefined還是null(JavaScript的表示淚目),所以不需要各種if else。
var name;
print(name); // null
複製程式碼
Dart型別
Dart是型別安全的語言,一切皆為物件的設計思路,任何型別都是物件型別,都繼承了頂層的Object。類如bool,int,null,函式,都是繼承於Object。
String name;
print(name is Object); // true
bool isPig;
print(isPig is Object); // true
int num;
print(num is Object); //true
void fun() {}
print(fun is Object); //true
複製程式碼
-
布林型別
在Dart中,使用bool關鍵字來定義布林型別,而布林型別只有兩個值,true和false,它們都是編譯時常量。
var c1 = true; var c2 = false; print(c1 is bool); // true print(c2 is bool); // true 複製程式碼
-
數值型別
在Dart中,使用num關鍵字來定義數值型別,num有兩個子類,分別為int代表整數型別和double代表浮點型別
num n = 10; print(n is int); // true num m = 1.1; print(m is double); // true 複製程式碼
除了常見的基本運算子,比如 +、-、*、/,以及位運算子外,你還能使用繼承自 num 的 abs()、round() 等方法,來實現求絕對值、取整的功能。你會發現,這些常見的運算子都繼承於num
-
字串型別
在Dart中,String 由 UTF-16 的字串組成。你可以使用${}內嵌表示式在字串中,如果是一個表示符,可以省略{}
var name = 'chong'; print('my name is $name'); // my name is chong print('toUpperCase: ${name.toUpperCase()}'); //toUpperCase: CHONG 複製程式碼
字串的拼接,與JavaScript一樣,Dart用“+”運算子來拼接。
var x1 = 'chong'; var x2 = '...'; print(x1 + x2); // chong... 複製程式碼
對與多行字串的拼接,Dart提供了類似JavaScript的模版字串功能。用三個單引號或者三個雙引號宣告
var str = ''' my name is chong '''; print(str); /* my name is chong */ 複製程式碼
-
集合型別
在Dart中,集合型別包含了陣列型別和字典型別,分別對應List和Map,宣告和使用,都跟Javascript差不多
var name = ['zhangsan', 'lisi']; name.add('wangwu'); name.forEach((f) => print('$f')); // zhangsan lisi wangwu var map = {"name": 'chong', "sex": 'boy'}; map['n'] = 'hello'; map.forEach((k, v) => print('$k: $v')); // name: chong sex: boy n: hello 複製程式碼
在定義name時,編譯器會推斷該List為List,所以如果add的是個int或者其他型別,會型別錯誤。同理 map 會被推斷成Map<String, String>,當然,也可以從定義的時候設定型別,而避免推斷錯誤。
var map = <String, String>{"name": 'chong', "sex": 'boy'}; map['n'] = 'hello'; map.forEach((k, v) => print('$k: $v')); // name: chong sex: boy n: hello 複製程式碼
Dart常量
Dart中定義常量的關鍵字有兩個,const和final,const的使用方法跟JavaScript的一樣。const和final的區別主要是const是在編譯時期已經確定的值,而final可以定義執行時的值,一旦執行結束,即不可改變。
```
var x = 10;
var y = 2;
final z = x / y;
print(z); // 5.0
const h = x / y;
print(h); // Error
```
複製程式碼
Dart運算子
Dart的大多數運算子與其他程式語言的類似。有幾個比較特殊的運算子,用來簡化處理null的情況
-
??運算子,x??y,表示x為空時,取y的值,x非空時,取x的值
var x; var y = 10; var z = x ?? y; print(z); // 10 複製程式碼
-
?.運算子,x?.y 如果x為null,跳過該語句,避免報錯
var x; print(x?.y); // null 複製程式碼
-
??=運算子, x??=y,如果x為null,把y賦值給x。如果x不為null,跳過。
var x = 10; var y = 20; x ??= y; print(x); // 10 var x; var y = 20; x ??= y; print(x); // 20 複製程式碼
在Dart中,一切皆物件,所以運算子也是物件成員函式中的一部分。當你在某些應用場景需要複寫運算子時,Dart也提供了複寫機制,只要通過 operator 關鍵字複寫即可.
class Demo {
var x, y;
Demo(this.x, this.y);
Demo operator +(Demo z) => Demo(x + z.x, y + z.y);
bool operator ==(Demo v) => v.x == x && v.y == y;
}
var x = Demo(3, 3);
var y = Demo(2, 2);
var z = Demo(1, 1);
print(x == (y + z)); // true
複製程式碼
四、函式
Dart的函式由返回值、函式名、引數、函式體4部分組成,函式也是物件,它的型別為Function,這也意味著函式可以被定義為變數和作為函式引數。
bool isCheck(int x, int y) {
return x == y;
}
void printBool(Function check) {
print('${check(1, 1)}');
}
printBool(isCheck); // true
複製程式碼
Dart函式也支援箭頭表示式,使用方法跟Javascript一致。如上面的例子可以簡化為
bool isCheck(int x, int y) => x == y;
void printBool(Function check) => print('${check(1, 1)}');
printBool(isCheck); // true
複製程式碼
作為集大多數語言優點為一身的程式語言,Dart設計非常靈活的函式傳參設計。設計了通過{}指定傳參,設定了通過[]設定可選引數。這也使Dart的程式碼更加簡潔優雅。不會像JavaScript一樣,如果函式需要三個引數,前兩個為空時,必須佔位。下面通過一個例子來記錄一下Dart函式的傳參。
void demo1({int x, int y}) => print('$x,$y');
demo1(y: 2); // null,2
void demo2(int x, [int y]) => print('$x,$y');
demo2(1); // 1,null
demo2(1, 2); // 1,2
void demo3(int x, int y) => print('$x,$y');
demo3(1, 2); // 1,2
demo3(1); // Error
void demo4(int x, {int y}) => print('$x,$y');
demo4(1); // 1,null
demo4(1, y: 2); // 1,2
demo4(y: 2); // Error
複製程式碼
五、類
物件是類的例項,在Dart裡,所有物件都繼承了頂層的Object,Dart中的類定義,例項話,方法引用,跟JavaScript ES6差不多。差別點是Dart中通過 "_" 來表示私有,宣告變數和方法時,在前面加上下劃線,表示為private,沒加的,表示為public。
class Cat {
var color, tail; // 顏色、尾巴
Cat(this.color, this.tail);
printInfo() {
print('這是一隻${color}毛髮, ${tail}尾巴的貓?');
}
}
var cat = new Cat('藍色', '長');
cat.printInfo(); // 這是一隻藍色毛髮, 長尾巴的貓?
複製程式碼
-
建構函式
Dart中,類的建構函式有同名建構函式和命名建構函式兩種,同名建構函式,如上面程式碼所示,與類同名。而命名建構函式,用以下方式定義
class Cat { var color, tail; // 顏色、尾巴 Cat(this.color, this.tail); Cat.defaut(var color) : this(color, '短'); // 重定向建構函式,用":"符號呼叫 printInfo() { print('這是一隻${color}毛髮, ${tail}尾巴的貓?'); } } var cat2 = Cat.defaut('白色'); cat2.printInfo(); // 這是一隻白色毛髮, 短尾巴的貓? 複製程式碼
-
複用
在物件導向程式語言中,複用是個很重要的概念,很多程式語言都有繼承承,介面等概念,來實現程式碼的複用。Dart也不例外,Dart中,也引入了繼承,介面的概念。
class Animal { var color, tail; Animal(this.color, this.tail); printInfo() { print('這是一隻${color}毛髮, ${tail}尾巴的貓?'); } } class Cat extends Animal { var type = '大型'; Cat(color, tail, {type}) : super(color, tail); @override printInfo() { print('這是一隻${color}毛髮, ${tail}尾巴的貓?,屬於${type}貓科'); } } class Dog implements Animal { @override var color, tail; @override printInfo() { print('這是一隻小狗'); } } var cat = new Cat("黑色", "長")..printInfo(); // 這是一隻黑色毛髮, 長尾巴的貓?,屬於大型貓科 var dog = new Dog()..printInfo(); // 這是一隻小狗 複製程式碼
除了繼承和介面實現複用外,Dart還提供了Mixins方式。Mixins的中文意思是混入,就是在類中混入其他功能。在Dart中可以使用mixins實現類似多繼承的功能。
class Poultry { printInfo() { print('這是一種家畜'); } } class Big with Poultry {} var big = new Big().printInfo(); // 這是一種家畜 複製程式碼