<style> table th:first-of-type { width: 20%; } table th:nth-of-type(2) { width: 30%; } </style> # Boso的Dart學習筆記 Dart 由Google於2011年發布 適用於開發App、Web、桌面應用程式等 * **屬於單執行緒的語言:** 簡單說就是程式碼會由上而下依序執行 * **物件導向型程式(OOP):** 每個對象都是一個實例 Object是所有類的父類 * **靜態語言:** 在編譯的時候進行型別檢查 而動態語言會在執行中檢查 * **強類型語言:** 型別判定明確 不會進行隱式轉換 * **接受AOT跟JIT兩種運行方式:** * **空安全 :::info **AOT (Ahead of time)** 靜態/提前編譯 指在運行前 先翻譯好所有機器碼 **JIT (Just in time)** 動態/及時編譯 指一句一句邊翻譯邊運行 ::: # 資料型態 | 型態類別 | 解釋 | |:-------- |:------------------------------------------| | String | 字串 | | bool | 布林值 | | int | 整數 | | double | 浮點數 | | num | 同時支持整數及浮點數 為int與double的父類別 | | List<資料型態> | 可重複的有序陣列集合 接近Array | | Set<資料型態> |沒有索引值且不可重複的集合| | Map<key資料型態,value資料型態> | 字典集合 (Key : Value)| ## 宣告變數 * **Dart會根據等號後面的資料型態進行型別判定** 基於強類型語言 除了**dynamic**、**object** 一旦宣告了資料型態後就不能再宣告其他型態 * 沒有預設值 值為**null** * 不能重複宣告 ### var 宣告後不能更改型態 但能修改值 ```dart= var a = 1; a = 2; //2 a = '2'; //error var a = 3; //error //建議使用var明確宣告資料型態較佳 ``` ### dymaic 動態宣告類型 也就是說它可以修改資料型態與值 ```dart= dynamic b = 1; b = 2; //2 b = '2'; //'2' dynamic b = 3; //error ``` ### const 常數 在**編譯**的時候宣告一個不可變動的常態 多為建立一個不變的常數使用 如果在**class**中定義**const** 則必須加上**static**關鍵字 才不會發生錯誤。 ```dart= const c = 1; c = 2; //error c = '2'; //error const c = 3; //error ``` ### final 常數 在**專案執行**的時候宣告一個不可變動的常態 不能重複宣告及變動值 (ex:宣告一個a+b的值 而這個a+b不能再修改) ```dart= final d = 1; d = 2; //error d = '2'; //error final d = 3; //error ``` :::warning ### const 跟 final 的差異 **const**是在編譯時就能確定值的常數 多用於**List、Map、Class**、運算、字串拼接、布林等 使用等 final是執行時確定值 用於從函數返回、建構函數中初始化等 ::: ## String 字串 * 可使用單引號('')或雙引號("") * 利用 ${ } 字串插值 * 使用三個單引號(''')或三個雙引號(""") 建立多行字串保留內在格式 * 使用r建立原始raw字串(轉義字元等特殊字元會輸出出來 不會自動被轉義) ```dart= var Name = '' 或 String Name = '' ``` ### 基本字串使用 ```dart= String.length //字串長度 String.isEmpty //字串是否為空 StringA + StringB //變數字串連接 '123' '456' //字串連接,'123456' String.toUpperCase() //轉大寫 (toLowerCase轉小寫) String.trim() //去除空格 ``` ### 字串轉換 ```dart= num.parse(String) //字串轉數字 int.toString() //數值轉字串 .runtimeType //判定資料型別 ``` ### 字串分割 ```dart= String.substring(0, 2) //取0到1 String.substring(3) //指定從索引3開始到結束 String.split(',')//使用,分割 返回的是一個List ``` ### 字串判斷 ```dart= String.startsWith('aa') //是否以aa作為開頭 String.endsWith('aa') //是否以aa作為結尾 String.contains('aa') //是否包含aa ``` ### 字串查詢 ```dart= String.indexOf('Str') //取得第一個符合條件的index,0 String.indexOf('tr',3) //從索引3開始找'tr' 找不到就會返回-1 String.lastIndexOf() //同理 但從由後往前找 ``` ## List 集合 * 使用 [ ] 包住物件 * 可以先定義陣列內的資料型態 **List**<資料型態> 也可混和陣列定義 * **List**存放的是一連串有序的物件,在 **List** 裡面的項目是可以重複的。 * 是**Iterable**的子類別 可迭代 ```dart= var Name = [1,1.2,'2'] 或 List<int> Name =[1,2] var Name = List(2) //定義List陣列長度 ``` ### 基本List使用 ```dart= List.length //陣列長度 List.first //獲取陣列第一個元素 (last 最後一個) List.reversed //獲取倒敘的元素 List.isEmpty //陣列是否為空 List.getRange(2,4) //查詢範圍2到3的元素 以(,)方式返回 List.sublist(2,4) //查詢範圍2到3的元素 以[,]方式返回 List.sublist(2) //從索引2開始的所有資料 List.sort(a-b) //排序 a-b為升序 b-a為降序 ``` ### List添加、刪除 ```dart= List.add() //添加元素在後方 List.addAll(List2) //添加多個元素在後方 List.remove() //刪除指定元素 List.removeAt(索引) //刪除指定的索引 List.removeLast() //刪除最後一個 List.removeRange(2,4); //刪除範圍2到3的元素 List.removeWhere((e)=> return 條件) List.clear() //刪除所有元素 List.insert(索引,元素) //指定索引新增 List.insertAll(索引,元素) //指定索引新增多個元素 ``` ### 元素修改 ```dart= List.setRange(2,4,[要更改的元素陣列]) //更改範圍2到3的陣列 List.setAll(2,[要更改的元素陣列]) //從索引2開始更改元素陣列 List.replaceRange(0,2,[元素]) //將索引0到2的替換為一個元素 List.join('&') //將陣列用「&」拼接成字串 List.toSet() //陣列去掉重複的元素 List.forEach((e){}) //遍歷集合中每個元素 對元素進行修改 List.map(e){} //按指定條件修改並返回一個陣列 ``` ### List判斷 ```dart= List.any((i)=>i>2) //判斷是否有滿足條件(>2)的元素,true List.every((i)=>i>2) //判斷所有元素是否都滿足設定條件,true List.contains(3) //判斷陣列中是否包含3,true List.firstWhere((i)=>i>2) //獲取滿足條件的第一個元素 (lastWhere最後一個) List.indexWhere((i)=>i>2,索引) //從指定索引開始 獲取滿足條件的第一個元素 ``` ### 展開運算子 ...list/...?list **Dart 2.3** 新增了展開運算子 (Spread Operator),可以將兩個 **List** 結合在一起。 ```dart= List<int> list1 = [4,5,6]; List<int> list2 = [1,2,3, ...list1]; //1,2,3,4,5,6 ``` **非空展開運算子**:若使用展開運算子時 若 **List1** 未定義值 那麼**List**展開不了就會報錯<br>可用**非空展開運算子**檢查要添加的 **List、Map、Set** 是否為**null** 若不是即可添加 ```dart= var list3 ; List<int> list4 = [1,2,3,...?list3]; //1,2,3 ``` ## Map 集合 * 使用 { } 包住物件 一定要有一個**key**和**value** * **key**不能相同 但**value**可以相同 * **key**不可為**null** **value**可以是空字串或是**null** * 字串使用雙引號定義 避免使用跳脫符號。 ```dart= var Name ={ //無須特定資料型態 'a':1, 'b':true, 'c':'a3' }; Map<String,String> Name ={ //鍵值須特定資料型態 'a':'a1', 'b':'a2', 'c':'a3' }; var Name = new Map(); //先定義字典再宣告其他鍵值 Name['key'] = 'value'; ``` ### 基本Map使用 ```dart= Map.length //字典長度 Map.isEmpty //字典是否為空 Map.keys //key的集合 Map.values //value的集合 ``` ### Map添加、刪除 ```dart= Map['key'] = 'value'; //新增/修改一組key Map.remove('key'); //移除一組鍵值 Map.removeWhere(key,value){ return 條件 }; //移除多組鍵值 Map.update('key', (value) => value * 2); //根據指定的key進行修改 同時本身也會修改 Map.updateAll((key,value){}) //修改物件內所有的value 返回值 Map.containKey('key') //是否包含某個key containValue()是否包含某個值 Map.forEach((key,value){}) //遍歷Map中每個鍵值修改 Map.addAll(map2) //合併字典 Map.putIfAbsent('key',()=>) //插入元素,如果該key不存在則執行=> ``` :::danger #### **addAll()** 無法直接合併不同資料型態的集合 需創一個空dynamic型別 再加入不同型態的集合 ```dart= Map<String, int> map1={ "a": 1, "b": 2, }; Map<String, double> map2={ "c": 3.14, "d": 4.2, }; Map<String, dynamic> map12 = {}; // 可以存放不同型態的值 map12.addAll(map1); map12.addAll(map2); // map1 的值已是 int,可以直接合併 ``` ::: ## Set 集合 **實戰中常用於資料結構處理** ex:去除重複字元、判斷元素間是否有交集、聯集或差集等。 * 使用 { } 包住物件 中間以 , 來分割 * 集合中不能放重複的物件 也沒有索引 * 基於實作**LinkedHashSet** **Set**還是會保存元素存入的順序 所以**Set**是可以迭代的 ```dart= Set<int> sets ={1,2,3,4,5}; ``` ### 基本Set使用 ```dart= Set.from(List); //整理list中重複的元素 並轉為Set Set.isEmpty //是否為空 Set.length //集合的長度 ``` ### Set添加、刪除 ```dart= Set.add() //添加元素在後方 Set.addAll() //添加多個元素在後方 Set.remove() //移除元素 ``` ### 常用Set方法 ```dart= Set.contains() //是否包含指定物件 Set.foreach((){}) //遍歷集合中每個元素 對元素進行修改 set1.difference(set2) //差集 set1.intersection(set2) //交集 set1.union(set2) //聯集 ``` # 函數語法 * 函數是物件 也是一種**Funtion**型態 可以當作參數、變數 * 每個程式都必須有一個 **main()** 函數作為入口 * 有兩種代入參數的方式 命名及位置 * 參數可選擇必要及非必要參數 * 所有函數都返回一個值 沒有值就是null ## 基本函數用法 函式的參數是在定義一個函式時需要的變數 ```dart= void function(資料型態 參數){ }; function() //呼叫函數 ``` ## 可選參數 **命名或位置參數可以選擇參數的傳入值** 但需添加 **?** 來標記該參數可為空值 ### 命名參數 { }: ### 須變數名稱 無須按順序填呼叫函數 ```dart= void function(String name , {int? age}){ }; function('bob' , age:15) ``` 在代入參數前 使用 **required** 將該參數變為必填參數 ```dart= void function({String? name , int age ,required String sex}){ }; function(String:'bob' , sex:'boy') ``` ### 位置參數 [ ]: 無須變數名稱 但要照順序填呼叫函數 ```dart= void function(String name , [int? age]){ }; function('bob' ,15) ``` ### 默認預設值: 若參數為null 則自動指定為默認的參數 ```dart= void function(String name , [int? age=16]){ print( 'Hi Im $name , My age is $age'); } function("Bob") //Hi Im Bob , My age is 16 ``` ### 匿名函式 <!-- ### if else判別式 ```dart= if(條件){ ... }else if{ ... }else{ ... } ``` ### For..迴圈 ```dart= for(var i=0;i<10;i++){ ... } ``` --> -->