---
# System prepended metadata

title: Dart 學習筆記

---


<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++){
   ...
   }
``` --> -->