壹、Types – Collections 參見: Dart Language: Collections
一、List List定義
List宣告範例 我們以外層為中括號包裹元素,並以逗號分隔的方式來定義陣列,下述兩種都是宣告陣列的方式
1 2 3 4 5 6 7 var list = [1, 2, 3]; //數字陣列 var list = [ 'Car', 'Boat', 'Plane', ]; //字串陣列,最後的逗號不影響宣告,但可以防範複製錯誤
List宣告範例
List基本性質範例 在下述例子中,我們可以看到基本的List性質,包含陣列長度計算、陣列位址計算、修改方式等。
注意: 因為list是由0 作為第一元素,因此這裡的[1]代表的是陣列中的第二個元素,也就是’2’,所以陣列的表示位址就是由[0]~[陣列長度-1],以下述範例而言,就是[0],[1],[2]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void main() { // 創建一個 List var list = [1, 2, 3]; // 檢查 List 的長度 print('List 的長度是 ${list.length}'); // 檢查 List 中的元素 print('List 中的元素是 $list'); // 更改 List 中的元素 list[1] = 1;//因為list是由[0]作為第一元素,因此這裡的[1]代表的是陣列中的第二個元素,也就是'2' // 再次檢查 List 中的元素 print('List 中的元素是 $list'); }
List使用範例
二、Sets:集合 Set定義
Set宣告範例 我們以外層為大括號包裹元素,並以逗號分隔的方式來定義Set
1 2 3 4 var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'}; //鹵素包含以下幾種元素集合 var names = <String>{};//創建空集合,等義於 Set<String> names = {};
Set基本性質範例 我們可以使用add()的方式將單一元素加入原有的集合中,例如下列範例將’fluorine’加入elements 集合;或是使用addAll()將一集合內全部元素加入另一集合中,例如下列範例將alogens 集合中的所有元素加入到 elements 集合中;而同樣的,我們也可以用.length來得到集合長度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void main() { // 定義 halogens 集合,包含氟、氯、溴、碘和砹等元素 var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'}; // 定義一個空的 elements 集合 var elements = <String>{}; // 將 'fluorine' 加入 elements 集合 elements.add('fluorine'); // 將 halogens 集合中的所有元素加入到 elements 集合中 elements.addAll(halogens); // 確保 elements 集合的長度為 5 assert(elements.length == 5); // 輸出 halogens 集合的元素 print('Halogens: $halogens'); // 輸出 elements 集合的元素 print('Elements: $elements'); }
Set基本性質範例
三、Maps Map定義
是一種無序的集合,其中元素是鍵(Key)值(Value)對應關係。
的鍵(Key)可以是任何類型,包括數字、字符串、對象等。
的值(Value)可以是任何類型,包括數字、字符串、對象等。
可以使用迭代器來遍歷元素。
可以使用包含運算符來檢查元素是否存在於 Map 中。
可以使用 keys()、values() 和 entries() 等方法來獲取相互的對列表。
Map宣告範例 我們以外層為大括號包裹元素,並以逗號分隔每組key-value值的方式來定義,每組key與value間以分號:作為連結
1 2 3 4 5 6 7 8 9 10 11 12 13 var gifts = { // Key欄位: Value欄位,Key欄位紀錄禮物序號,Value欄位紀錄禮物內容 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' }; var nobleGases = { // Key欄位: Value欄位,Key欄位紀錄原子序,Value欄位紀錄元素名稱 2: 'helium', 10: 'neon', 18: 'argon', };
Map宣告範例
而我們也可以將”gifts” ,”nobleGases”變數用Map構造函式Map<String, String>與Map<int, String>的方式進行宣告,
1 2 3 4 5 6 7 8 9 var gifts = Map<String, String>(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings'; var nobleGases = Map<int, String>(); nobleGases[2] = 'helium'; nobleGases[10] = 'neon'; nobleGases[18] = 'argon';
Map宣告範例
Map基本性質範例 我們可以用[]=的方式來新增一個key-value對,並且用.length的方式來確認長度。尤以下範例中,我們首先定義了一個gifts的Map物件,一開始只有一個key-value對,而後我們再新增第二個禮物(中括號內的為key值,而等號右方的為value值),在兩次的print(gifts)中我們可以看出差別,而中間的assert()函式可以幫助我們進行條件檢查(條件不符合時會出現警告)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void main() { // 定義一個名為 "gifts" 的 Map 物件,包含一個 key-value 對。 var gifts = {'first': 'partridge'}; // 在 Map 中新增一個 key-value 對,新增第二個禮物設為 'calling birds'。 gifts['second'] = 'calling birds'; print(gifts);//印出的gifts裡面有 first和second // 斷言:檢查第一個禮物是否是 'partridge'。 assert(gifts['first'] == 'partridge'); // 斷言:檢查第三個禮物是否為 null。 assert(gifts['third'] == null); // 再次在 Map 中新增一個 key-value 對,新增第三個禮物設為 'doll' gifts['third'] = 'doll'; print(gifts);//印出的gifts裡面有 first,second和third // 斷言:檢查 Map 的長度是否為 3。 assert(gifts.length == 3); }
Map基本性質範例
四、Operators Spread operators: 展開運算符
以下示範兩種範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void main() { //---------"..."展開運算符---------- // 定義一個整數串列 list1 var list1 = [1, 2, 3]; // 使用展開運算符將 list1 的元素展開到 list2 中 var list2 = [0, ...list1, 4, 5]; // 輸出 list2 的內容 print('展開運算符範例: $list2'); // 輸出:[0, 1, 2, 3, 4, 5] //---------"?... "安全展開運算符---------- // 定義一個可能為 null 的整數串列 nullableList List<int>? nullableList = null; // 使用安全展開運算符將 nullableList 的元素展開到 list3 中 var list3 = [0, ...?nullableList]; // 輸出 list3 的內容 print('安全展開運算符範例: $list3'); // 輸出:[0] }
展開運算符範例
Control-flow operators 我們可以透過在集合(如串列或 Map)中加入if, for的方式來宣告,以便簡化宣告流程的判斷或迭代,我們可以由以下範例看到三種用法,包含if集合、if-case集合與for迴圈集合用於列表的用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 void main() { //---------if集合用於列表範例------------- bool promoActive = true; // 建立一個導航串列 "nav",並加入if條件判斷 var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet']; print('if集合用於列表範例: $nav'); // promoActive為true,條件成立,輸出:[Home, Furniture, Plants, Outlet] //---------if-case集合用於列表範例--------- String login = 'Manager'; // 建立另一個導航串列 "navWithLogin",並加入if-case判斷 var navWithLogin = ['Home', 'Furniture', 'Plants', if (login == 'Manager') 'Inventory']; print('if-case集合用於列表範例: $navWithLogin'); // login為'Manager',條件成立,輸出:[Home, Furniture, Plants, Inventory] //---------for迴圈集合用於列表範例--------- var listOfInts = [1, 2, 3]; // 建立一個字串串列 "listOfStrings",並加入for迴圈 var listOfStrings = ['#0', for (var i in listOfInts) '#$i']; print('for迴圈集合用於列表範例: $listOfStrings');//輸出for迴圈迭代後結果 }
貳、Types – Records: 紀錄 參考資料: Dart Language: Records
一、Record syntax: 紀錄語法 Records範例 在Records中,我們使用”逗號”為括號內的每筆資料作分隔,並且可以用getter,$或指定變數的方式取值。其中,當我們使用getter時是針對沒有命名的變數進行取值,所以可以由下列範例中的$2印出’last’字串,可以看到a, b兩個已命名變數會被跳過
1 2 3 4 5 6 7 void main() { var record = ('first', a: 2, b: true, 'last'); print(record.$1); // 輸出第一欄位,'first' print(record.$2); // 輸出第二欄位,'last'(跳過命名的變數a,b) print(record.a); // 輸出變數'a'的值 print(record.b); // 輸出變數'b'的值 }
record範例
我們由DartPad的Documentation欄位可以看到這是一個由兩個String, 一個int變數”a”與bool變數”b”組成的record變數
Records用於回傳資料定義 而我們也可以用records的方式來定義回傳的資料,下方的(int, int)代表Records類型的註釋
1 2 3 4 5 6 7 8 9 10 (int, int) swap((int, int) record) { //用records的方式對回傳函式參數值進行規範 var (a, b) = record; return (b, a); } void main() { var (a, b) = swap((1, 2));//交換前的數字陣列是(1,2) print('交換後的a: $a'); // 輸出2 print('交換後的b: $b'); // 輸出1 }
Records類型註釋範例
Records宣告,包含變數與直接給定值 在宣告Records時,我們可以選擇連同變數與型別一起宣告的方式(用大括號將變數類型與名稱包含)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void main() { //--------宣告Record變數與內部變數、型別----------- ({int a, bool b}) record;//用大括號表示Records內的變數宣告 // 給予Records初始化值: (a: 123, b: true) record = (a: 123, b: true); print('變數a: ${record.a}'); // 輸出 a 變數的值 print('變數b: ${record.b}'); // 輸出 b 變數的值 //--------宣告Records變數與內部型別--------------- (int, bool) record2; // 給予Record2初始化值: (a: 123, b: true) record2 = (123, true); print('欄位一: ${record2.$1}'); // 輸出欄位一的值 print('欄位二: ${record2.$2}'); // 輸出欄位二的值 }
二、Record types 在我們未宣告變數時,系統也會明確知道Records內部真值的型別
1 2 3 4 5 6 7 8 9 10 void main() { (num, Object) pair = (42, 'a'); var first = pair.$1; // 靜態型別`num`, 運行型別`int`. var second = pair.$2; // 靜態型別 `Object`, 運行型別 `String`. print(first.runtimeType); // 輸出運行型別,int print(second.runtimeType); // 輸出運行型別,String }
Record types範例
三、Record equality 兩個 record 相等如果它們有相同的形狀(變數集合)和相應變數的值相同。 由於命名”順序”不是 record 的形狀的一部分,因此命名變數的順序”不影響”相等性。
以下是一些概念例子:
({x: 1, y: 2}) 和 ({y: 2, x: 1}) 是相等的,因為它們有相同的形狀(兩個字段 x 和 y)和相應字段的值相同。
({x: 1, y: 2}) 和 ({x: 1, y: 3}) 是不相等的,因為它們 y 的值不同。
({x: 1, y: 2}) 和 ({z: 1, y: 2}) 是不相等的,因為它們有不同的形狀(一個x 和另一個 z)。
五、Multiple returns 我們可以用Records的方式來簡化具有多重回傳值的情況,以下列範例為例,可以一次性的將多種型別與函數值對應在userInfo的函式中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void main() { // 定義一個 JSON 對象 final json = { 'name': 'Dash', 'age': 10, 'color': 'blue', }; // 使用 record 模式獲取 name 和 age 字段的值 var (name, age) = userInfo(json); // 輸出 name 和 age 的值 print('Name: $name'); print('Age: $age'); } (String, int) userInfo(Map<String, dynamic> json) { // 返回 name 和 age 字段的值 return (json['name'] as String, json['age'] as int); }
Multiple returns範例