如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 DevTech Ascendancy Hub
本篇文章對應的是 探討 Dart 語言:宣告、數據類型、操作符 | 從基礎到應用指南
Dart 是單線程(單執行序),GC 回收使用 CMS 機制,也就是使用分代回收機制 (新生代、老年代)
以下會以 Java 語言進行比較,提及與 Java 的差異,Dart 與 Groovy 也有部分相像
使用指令運行,該指令存在於 Flutter SDK 的資料夾內,將該路徑加入環境變數,重啟 AS 就可以在終端機下達指令 dart xxx.dart
Dart 指令路徑:
${flutter_sdk}\bin\cache\dart-sdk\bin
Dart 語言的特性:
所有的東西都是物件,甚至包含 Java 的基礎類型 (eg. int)
Dart 是弱類型語言,不必指定數據類型
指定數據類型、const 常量可以提高運行速度
Dart 是 AOT (Ahead Of Time
) 編譯,在安裝前會先進行預編譯,編譯成本地代碼 (Dart to java or object-c)
Dart 也可以 JIN (Just In Time
) 編譯
以 60fps 運行的流暢動畫和轉場,可以在沒有鎖的時候進行物件分配 & 垃圾回收,Dart 避免了線程的搶佔 (線程的特性與 Java 不同)
代碼即是布局,不須另外使用另一個語言建構 (Android 使用 Xml 建構)
Dart 程式特性:
統一的程序入口 main()
,這一點如同 C、Java 語言
並沒有 public
、protected
、private
的參數訪問限制概念,但 私有可以變量可以使用下滑線 ( _
) 來表示
支持異步處理 anync
/ await
所有函數都有函數返回值! 如果沒有返回值默認返回為 null
Dart 中常見的第三方庫有如下表所示:
庫名 | 描述 |
---|---|
dart:async |
異步編成支持,提供 Future & Stream |
dart:collection |
針對 dart:core 提供更多的集合支持 |
dart:convert |
不同類型(JSON 、UTF-8 ) 的字符轉換 |
dart:core |
基礎核心庫 |
dart:html |
網頁開發用到的庫 |
dart:io |
文件讀取的 IO |
dart:math |
函數、隨機算法等等 |
dart:svg |
SVG 動畫 |
Dart 變數有幾個特色
一般我們在宣告類別時必須寫清楚類型,而 dart
可以直接使用 var
作為類型宣告 (Dart 的編碼風格),在 Java 10
、kotlin
中也有 var
宣告方式 | 解釋 | Example |
---|---|---|
類型宣告 |
如同一般 Java 宣告,必須寫清楚是哪種類型的數據(之後會一一介紹 Dart 的類型) | Person person = new Person(); |
Object |
任意類型 | Object person = new Person(); |
var |
自動推導類型 (若是不清楚就要考慮少用),並且推倒後就不可以在更改類型 | var person = new Person(); |
dynamic |
運行時確定數據類型,相對來說會慢一些,在沒有初始化時默認為 null | dynamic person = new Person(); |
其中較為特別的是 dynamic
類型: 它不在編譯期間定義,它在「運行期間才決定類型」;以下是不同宣告方式的範例
不同語言的 var
所造成的差異(編譯期間)
在 JS 中也有 var
這種宣告方式,但 JS 是「動態類型語言」(python 也是),可在賦予值後重新設定不同的類型
Dart 則是「靜態類型語言」,在賦值時就被定義(自動推倒)
Java 中我們可以看到 final
,C/C++
中可以看到 const 描述,其實被這兩者描述過後,該變數都會變為不可再修改的值 (轉為常數),而 final、const 仍然存在著差異
描述 | 作用時 | 範例 |
---|---|---|
final | 運行期間 確定 | final String FINAL_NAME = "Apple" |
const | 編譯期間 確定 | const String CONST_NAME = "Banana" |
運行時 final
不可以賦予給編譯時常量 const
,因為 const
必須編譯期就確定,而相反操作過來就可以,因為 final 運行時再確認即可
所以被
const
描述的稱之為常量,它的效能往往會比被final
描述的更好,因為它在編譯過後就被確定類型
const
& final
不可以跟 var
一起使用
Dart 是屬於 強類型語言,並且 沒有基礎數據類型 (Java 有 8 大基礎數據),int
、long
…都是實體的物件,下圖是 dart 語言的 int 類
Dart 有內置的七種類型 (7 個仍是類)
內置類 | 介紹 & Java 比較 | 範例 |
---|---|---|
num |
分為整數、浮點數 | int、double |
String |
儲存大小為 UTF-16,可用單、雙引號,並可嵌套使用 (省去跳脫字元 \ ) |
String str = 'A' or "B" |
bool |
如同 Java 使用 | bool y = false; |
List<E> |
不使用 ArrayList,可直接使用 index 取值,增加數值使用 add | List list = new List(1); var list = List(1); |
Map<K, V> |
一樣是 Key & Value 相對,取值方式可以使用中括號 [] ,中括號內是放置 key 並非 index |
Map map = ['A': 1, 'B': 2] |
Runes |
Unicode 字符,將 32 位的 Unicode 編碼轉為字符串 | var a = '\u{1f9f99}' |
Symbol |
可以看做 C/C++ 的宏,編譯時的常量 | Symbol #Hello |
num 所有數的父類,有 int
& double
兩個子類 (但是並無 short
、float
、long
… 其他數據類型)
Dart 與 Java 語言對於數字類型的看待、差異
Dart 只有 int
(整) & double
(浮點數),而沒有 float、short…
數字類型佔用字節數(byte
)的差異:int 在 java 中占用 4 個字節,dart 則會依照平台而改變,屬於動態改變自節數
String 類對於高級語言來說是個大家都通認的類型,這邊就不過多介紹,主要來比較一下 Dart 與 Java 語言對於 String 類型不同的地方
基礎差異:總體來說比起 Java 使用起來更加的自由
Dart 對於字串的解釋方式可以使用「字符串插值」(String Interpolation
),不再像是 Java 只能透過 +
號來串接字串
可以混用單、雙引號來表達字串
使用 '''
、"""
可以包裹換行的字串
並且可以透過在字串前添加 r
來告訴 Dart 該字串是「元數據」(不需要解譯跳脫字符等等)
特殊字元差異
Java 每個 String 大小不可超過 2 個 byte,若超過則必須分開(這是因為 Java 目前採用 UCS-2
編碼)
Dart 則可以超過 2 byte,超過只需使用 {}
即可 (若未超過則不用)
Dart String 字串長度的陷阱(關鍵字: 代碼點 & 代碼單元)
代碼單元:String#length 只是大部分是「字符長度」,但並不完全代表代碼單元數量… 假設字符串是以 UTF-16 編碼存儲的(Dart、Java 就是如此),一個代碼單元是 16 位的整數
代碼點:Unicode 編碼中每個字符對應的一個整數值,也就是儘管超過程式語言的代碼編制長度,也會算成是一個整數值
範例如下
Dart 的 bool 類型與 Java 並無太大的差異(Java use boolean
),同樣使用 true/false… 這邊只需要特別注意 對於 Dart 來說 bool 仍是物件,而對於 Java 來講它只是基礎類型
Dart 的 List 如同 Array 可以使用下標(index
)取值
以下我們會特別加入 const
的使用,並與 C/C++ 比較 (有相似之處);
const
如果放在宣告物件的描述,會讓該物件的引用、內容皆不可修改
但如果 const
只放在建立物件實例的描述,則該物件的引用可以修改,而物件的實例內容則不能修改!
我們可以使用 C/C++ 的 const 修飾指標來表達相同的功效,這樣會看的更加清晰(當然這是對於學過 C/C++ 的人來說會看出兩者個相同之處)
Map 使用跟 List 相似,也可以使用 const
修改(這裡就不特別說明 const 描述的位置造成的差異),特點是 可以使用 []
自動拓展,不需要像是 Java 使用 put()
函數做添加
Dart 的 Runes 類型是個特別的類型:
Dart 特別分出兩個單詞:代碼點、代碼單元
單詞 | 說明 |
---|---|
代碼點 codePointCount |
可以取出目前輸入數的數量,它不會按照字元的 Byte 數量來解釋字串長度 |
代碼單元 codeUnits |
經過編碼後才返回的 Byte 數量 |
Java 如何儲存超過 2Byte 的字串?
以往 Java String 類型無法放置超過 2Byte 的數據,如果要儲存就要使用 \u
開頭的方式來表達,範例如下
而 String#length()
方法是在 UCS-2
(Unicode
的其中一種)編碼下所返回的單元(Byte)數量
Symbol 標示符號,其概念類似於 C/C++ 的 define
宏概念,它可以用來定義常數;Dart 語言在使用 Symbol 類型時要在常數前加上 #
定義;範例如下…
操作符同樣是比較與 Java 相異、沒有的部分,至於與 Java 相同的操作符就不另外介紹
Dart 的類型判斷可以使用下表的幾個關鍵字
關鍵字 | 解釋 & 比較 | Java 使用 | Dart 使用 |
---|---|---|---|
as |
類型轉換,Java 使用括號強制轉型 | int b = (int)a; | int b = a as int; |
is |
類型判定,Java 使用 instanceof 判斷 | if(a instanceof Person) | if(a is instanceof) |
is! |
反向判定,注意 ! 使用在後面 |
if(!(a instanceof Person)) | if(a is! instanceof) |
??=
在 Dart 中以下這些操作符號 =
、+=
、-=
、\=
、*=
都可以使用,而 有一個較特別的是 ??=
操作符,它會先判斷該物件是否為 null,若為 null 則賦值
以 Java、Dart 兩種語言來比較:
操作符 ??=
使用範例如下:
??
除了基礎的三元表達式 condition ? todo1 : todo2
,Dart 還多了一種 ??
表達,它會先執行第一個敘述,若第一個敘述反為 null 則執行第二個敘述
以 Java、Dart 兩種語言來比較:
操作符 ??
使用範例如下:
.?
Dart 提供了安全操作符 .?
,若物件為 null 則直接返回 null,並不會往下執行函數
以 Java、Dart 兩種語言來比較:
操作符 .?
使用範例如下:
..
操作符號是 ..
,在同一個物件上可以連續調用該物件的函數、成員,可以避免創建臨時變量 (可以使用 C++ 理解,必須透過複製建構函數創造臨時物件進行賦值)
這種操作尤其可以使用在「建造者 builder 模式」
...
Dart 可以透過 ...
符號來「解構列表」的元素,將其轉為個別的元素,範例如下
Flutter
Dart