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