前言
Dart是Flutter SDK指定的語言,因此要學習Flutter,Dart是必須掌握的。關於Dart可以寫一本書了,這裡用一篇文章來介紹下Dart的精髓,帶你快速入門。和Java語言類似的部分,這篇文章就儘量不再講了。
1. Dart開發環境搭建
學習Dart語法最好需要用一個編輯器來實踐,這裡推薦使用IntelliJ IDEA。先下載Dart SDK,地址為:http://www.gekorm.com/dart-windows/
開啟IntelliJ IDEA,選單中點選File–>Settings–>plugins,在plugins的搜尋框中搜尋Dart並安裝,然後重啟IntelliJ IDEA。
點選File–>New Project–>Dart,按照下圖配置Dart SDK。
]
注意要選擇第三個選項Constole Application,否則會預設建立一個Web專案。點選Next然後配置專案的名稱就可以建立專案了。
在專案中的bin/main.dart中加入如下測試程式碼:
void main() {
print("Hello World");
}
點選選單的Run–>Run’main.dart’或者點選工具條的執行圖示,就能在控制檯看到輸出的結果:
2. Dart概述
Dart是谷歌開發的計算機程式語言,亮相於2011年10月,最新的版本是Dart2。Dart誕生的原因是谷歌的工程師出於對JavaScript的不滿,誕生的初期也贏得了部分前端開發者的青睞。但是這時JavaScript藉著NodeJS火了起來,在前端、後端、移動端無孔不入,Dart就漸漸被人遺忘了,可見Dart本身是具有很強的實力的,只是不大走運。谷歌並沒有放棄Dart,不遺餘力的推廣Dart:谷歌的Angular提供了Dart版本,指定Dart為新系統Fuchsia的官方開發語言,Dart為移動UI框架Flutter的開發語言,因此Dart又重新回到了人們的視野中。
Dart通常情況下執行在DartVM上,但是在特定情況下它也可以編譯成原生程式碼執行在硬體上,比如Flutter會將程式碼編譯成指定平臺的原生程式碼來提高效能。
3. Dart特性和重要概念
Dart的特性主要有以下幾點:
- 執行速度快,Dart是AOT(Ahead Of Time)編譯的,可以編譯成快速的、可預測的原生程式碼,這使得Flutter幾乎都可以使用Dart來編寫。也可以採用JIT(Just In Time)編譯。
- 易於移植,Dart可編譯成ARM和X86程式碼,這樣Dart可以在Android、iOS和其他地方執行。
- 容易上手,Dart充分吸收了高階語言特性,如果你已經熟悉C++、C、Java,可以在短短几天內用Dart來開發。
- 易於閱讀,Dart使Flutter不需要單獨的宣告式佈局語言(XML或JSX),或者單獨的視覺化介面構建器,這是因為Dart的宣告式程式設計佈局易於閱讀。
- 避免搶佔式排程,Dart可以在沒有鎖的情況下進行物件分配和垃圾回收,和JavaScript一樣,Dart避免了搶佔式排程和共享記憶體,因此不需要鎖。
Dart的重要概念有以下幾點:
- 在Dart中,一切都是物件,每個物件都是一個類的例項,所有物件都繼承自Object。
- Dart在執行前解析所有的程式碼,指定資料型別和編譯時常量,可以使程式碼執行的更快。
- 與Java不同,Dart不具備關鍵字public、protected、private。如果一個識別符號以下劃線
_
開始,那麼它和它的庫都是私有的。 - Dart支援頂級的函式如main(),也支援類或物件的靜態和例項方法,還可以在函式內部建立函式。
- Dart支援頂級的變數,也支援類或物件的靜態變數和例項變數,例項變數有時稱為欄位或屬性。
- Dart支援泛型型別,如
List<int>
(整數列表)或List<dynamic>
(任何型別的物件列表)。 - Dart工具可以報告兩種問題:警告和錯誤。警告只是說明程式碼可能無法正常工作,但不會阻止程式執行。錯誤可以是編譯時或執行時的。編譯時錯誤會阻止程式碼執行; 執行時錯誤會導致程式碼執行時報出異常。
4. Dart關鍵字
關鍵字 | |||
---|---|---|---|
abstract | dynamic | implements | show |
as | else | import | static |
assert | enum | in | super |
async | export | interface | switch |
await | extends | is | sync |
break | external | library | this |
case | factory | factory | factory |
catch | false | new | true |
class | class | null | try |
const | finally | on | typedef |
continue | for | operator | var |
covariant | Function | part | part |
default | get | rethrow | while |
deferred | hide | return | with |
do | if | set | set |
5. 變數
變數宣告使用var關鍵字,未初始化的變數的初始值為null,即便是數字型別的變數也是null。
var name = 'liuwangshu';
name變數的型別被推斷為String,也可以顯示宣告:
String name = 'liuwangshu' ;
如果物件不限於單一型別,可以指定Object或dynamic型別。
Object name = 'liuwangshu' ;
如果定義的變數不會變化,可以使用final或const來代替var,final變數只能設定一次。
final name = 'liuwangshu'
//name = 'zhangwuji' ; //會報錯
const變數為編譯時常量,如果const變數在類級別,可以使用static const。
const pi = 3.1415926;
const area = pi * 60 * 60;
const不僅僅用來定義常量,也可以使用const來建立常量的值。
var foo = const []; final bar = const []; const baz = [];//相當於`const []`
6. 基本資料型別
Dart的基本資料型別包括Number、String、Boolean、List、Set、Map、 Symbol、Runes。
6.1 Number
number型別為兩類:
- int:整數值不大於64位,具體取決於平臺。在Dart VM上,值可以是-2 ^63到2 ^63 - 1,如果編譯為JavaScript,允許值為-2^53 to 2^53 - 1。
- double:64-bit (雙精度) 浮點數,符合 IEEE 754 標準。
6.2 String
Dart 字串是 UTF-16 編碼的字元序列。 可以使用單引號或者雙引號來建立字串:
var s1 = '單引號適用於字串文字';
var s2 = "雙引號同樣有效";
可以在字串中使用表示式,用法是: ${expression}
。如果表示式是一個識別符號,可以省略 {}。
var s = '乾坤大挪移';
assert('張無忌的$s' ==
'張無忌的乾坤大挪移');
使用三個單引號或者三個雙引號可以建立多行字串物件:
var s1 = '''
第一行
第二行
''';
var s2 = """第一行
第二行""";
6.3 Boolean
Dart是強bool型別檢查,只有true物件才被認為是true。
var name = '張無忌';
if (name) {
print('明教教主');
}
上面的程式碼編譯不能通過,因為name是一個字串,而不是bool型別。
6.4 List
下面是一個List 的示例:
var list = [1, 2, 3];
List的第一個元素的索引是0,最後一個元素的索引是 list.length - 1 。
var list = [1, 2, 3, 4, 5, 6];
print(list.length);
print(list[list.length-1]);
6.5 Set
Dart中的Set是一組無序的集合。
var hero = ['張無忌', '風清揚', '張三丰', '獨孤求敗', '蕭峰'];
要建立一個空集,可以在{}前面帶有型別引數:
var heros= <String> {};
使用add()或addAll()方法將條目新增到現有集中:
var heros = <String>{};
heros.add('石破天');
heros.addAll(hero);
6.6 Map
Map是一個鍵值對相關的物件,鍵和值可以是任何型別的物件,每個鍵都是唯一的,而一個值則可以出現多次。
var player= {
// Keys Values
'20' : '斯諾',
'3': '艾弗森',
'40' : '希爾',
'8' : '麥基',
'55' : '穆託姆博'
};
使用Map建構函式也可以實現同樣的功能:
var player = new Map();
player['20'] = '斯諾';
player['3'] = '艾弗森';
player['40'] = '希爾';
7. 函式
Dart是一個真正物件導向的語言,函式屬於Function物件。這意味著,函式可以賦值給變數,也可以當做其他函式的引數。
void printName(String name) {
print('name is $name');
}
7.1 可選引數
可選引數可以是可選位置引數,也可以是可選命名引數,但不能同時使用。
可選命名引數
呼叫方法的時候,可以使用 paramName: value
的形式來指定引數的名稱,這樣就可以根據paramName得知引數的含義,提高程式碼的可讀性。
coffeeFlavor (sugar :true ,sugar :false );
定義函式時,使用{param1, param2, …}
的形式來指定命名引數:
coffeeFlavor ({bool sugar , bool sugar}) {
}
可選位置引數
把函式的引數放到 [] 中就變成可選位置引數了:
String go(String to, [String who]) {
var result = 'go to the $to';
if (who != null) {
result = '$result with $who';
}
return result;
}
7. 2 預設引數值
可以使用 =
來定義可選引數的預設值, 預設值必須是編譯時常量。 如果沒有提供預設值,則預設值為 null。
String go(String to, [String who= 'liuwangshu']) {
var result = 'go to the $to';
if (who != null) {
result = '$result with $who';
}
return result;
}
String result= go ('beijing');
7.3 main函式
每個應用都需要有個頂級的main() 函式來作為入口才能執行。 main()函式的返回值為 void 並且有個可選的 List<String>
引數。此前我們舉的例子都是在main函式中執行才能得已驗證:
void main(){
void printName(String name) {
print('name is $name');
}
printName('liuwangshu');
}
7.4 匿名函式
大部分函式都有名字,例如 main() 或者 printElement()。 可以建立沒有名字的匿名方法,格式如下所示。
([[Type] param1[, …]]) {
codeBlock;
};
下面的程式碼定義了一個引數為i(該引數沒有指定型別)的匿名函式。 list中的每個元素都會呼叫這個函式列印出來.
var list = ['張無忌', '風清揚', '張三丰', '獨孤求敗', '蕭峰'];
list.forEach((i) {
print(list.indexOf(i).toString() + ': ' + i);
});
8. 流程控制語句
Dart的流程控制語句如下:
- if 和 else
- for迴圈
- while和do- while迴圈
- break和continue
- switch和case
- assert
這些語句的大部分都和Java差不多,這裡主要講解for迴圈和switch語句。
8.1 for迴圈
標準的 for 迴圈:
var message = new StringBuffer("張無忌");
for (var i = 0; i < 3; i++) {
message.write('!');
}
List和Set等實現了Iterable介面的類還支援for-in
形式的遍歷:
var hero = ['張無忌', '風清揚', '張三丰', '獨孤求敗', '蕭峰'];
for (var h in hero) {
print(h);
}
8.2 switch和case
Dart中Switch語句通過使用 == 來比較整型、字串或者編譯時常量。被比較的物件必須都是同一個類的例項(不能是其子類),並且這個類不允許覆寫 ==。另外,列舉型別很適用於在Switch語句使用。\
String today='Friday';
switch(today){
case 'Monday':
print('星期一');
break;
case 'Friday':
print('星期五');
break;
}
9.捕獲異常
捕獲異常可以避免異常繼續傳遞。
try {
//...
} on OutOfLlamasException {
//...
} on Exception catch (e) {
print('Unknown exception: $e');
} catch (e) {
print('Something really unknown: $e');
}
使用on或者catch來宣告捕獲語句,也可以同時使用。其中on來指定異常型別,catch來捕獲異常物件。
確保某些程式碼不管有沒有出現異常都會執行,可以使用finally語句來實現。
try {
//...
} catch(e) {
print('Error: $e');
} finally {
//...
}
10.為類新增新的功能
Dart是一個物件導向程式語言,支援基於Mixin的繼承機制。Mixin可以理解為多繼承,在with關鍵字的後面為一個或者多個類。
class Person{
run(){
print('跑');
}
}
class Wushu{
use(){
print('乾坤大挪移');
}
}
class Zhangwuji extends Person with Wushu{
int age;
Zhangwuji(int age){
this.age=age;
}
}
void main() {
var zhangwuji=new Zhangwuji(30);
zhangwuji.run();
zhangwuji.use();
}
通過如上程式碼的驗證,Zhangwuji類擁有了Person和Wushu這兩個類的方法。
11.庫的使用
使用import來引入一個庫,對於Dart語言內建的庫,使用dart: scheme。 對於第三方的庫,可以使用檔案系統路徑或者 package: scheme。
import 'dart:io';
import 'package:mylib/mylib.dart';
import 'package:utils/utils.dart';
指定庫字首
如果匯入的兩個庫具有衝突的名字, 可以使用庫的字首來進行區分。 例如,如果library1和library2 都有一個名字為Element的類,可以這樣使用:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// ...
Element element1 = new Element(); //使用lib1中的Element
lib2.Element element2 = new lib2.Element(); //使用lib2中的Element
匯入庫的一部分
如果只使用庫的一部分功能,則可以選擇需要匯入的部分內容。其中show代表只匯入指定的部分,hide代表除了指定的部分都匯入。
// 只匯入foo
import 'package:lib1/lib1.dart' show foo;
// 除了foo,其他部分都匯入
import 'package:lib2/lib2.dart' hide foo;
延遲載入庫
延遲載入意味著應用程式可以在需要的時候再載入庫,使用延遲載入庫的場景主要有以下幾點:
- 減少APP的初始啟動時間。
- 執行A/B測試,例如嘗試各種演算法的不同實現。
- 載入很少使用的功能。
要延遲載入一個庫,需要先使用 deferred as來匯入:
import 'package:deferred/hello.dart' deferred as hello;
當需要使用的時候,呼叫loadLibrary() 函式來載入庫:
greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
12.非同步支援
Dart庫中包含許多返回Future或Stream物件的函式。這些函式是非同步的,它們在基本操作後會返回,而不等待該操作完成,例如讀取一個檔案,在開啟檔案後就返回了。
雖然看起來有點像同步程式碼,但是async和await的程式碼是的確非同步的。
await readFile()
要使用await,其方法必須帶有async關鍵字:
FileOperate() async {
var file= await readFile()
//其他處理
}
13.讓類可呼叫
如果Dart中的類實現了call()函式,那麼這個類可以當做方法來呼叫。
class JointFunction {
call(String a, String b, String c, String d) => '$a $b $c $d';
}
main() {
var jf = new JointFunction();
var out = jf("放","手","去","做");//1
print('$out');
}
在上面的示例中,JointFunction類定義了一個call()函式,它接收三個字串並拼接它們。這樣在註釋1處就可以呼叫JointFunction類了。
14.建立例項
在Java中建立例項可以用new,在Dart中你可以選擇用new,也可以選擇不用:
Element element = Element();
對於Android開發來說用new可能更習慣一些,可讀性也稍微好點,不用new的話顯得更簡潔,至於用不用new就看團隊的要求和個人的習慣吧,沒有絕對的好壞之分。
總結
Dart的知識點有很多,這裡只介紹了一部分我認為需要重點掌握的部分,如果想了解更多,可以檢視官方文件,關於Dart的學習可以結合Flutter邊寫邊學,不要只摳Dart的細節。
By: Laravel-China 寧澤林
MyBlog: nizer.in