今天我們要來談談關於 Dart 的迴圈、判斷式以及函式的語法,馬上開始吧!
條件判斷式是執行邏輯判斷中重要的程式區塊,在 Dart 中提供了三種條件判斷式的語法
if
if-else
是最常見的條件判斷式
if (weather.now == weather.isRaining) {
// 如成立執行此區塊
print('下雨了');
} else if (weather.now == weather.isCloudy) {
// 當條件 1 不成立時,判斷條件 2,若成立則執行此區塊
print('刮風了');
} else {
// 當條件 1, 2 接不成立則執行此區塊
print('天氣還不錯');
}
if-case
if-case
是 if
的變形,表是 if
判斷式滿足 case
的情況則執行該區塊
需 Dart version >= 3.0 才支援此語法
if (weather.now case weather.isRaining) {
print('下雨了');
}
switch
switch
針對單個判斷式進行評估,並且與一系列的 case
進行比對,也可設定 default
來執行預設行為。與其他程式語言比較不同的是,當滿足一個 case
時不需要再 break
離開整個判斷式。
switch (weather.now) {
case weather.isRaining:
print('下雨了');
case weather.isCloudy:
print('刮風了');
default:
print('天氣還不錯');
}
迴圈可以將某個區塊的程式碼重複的進行運算,並且可以設定執行條件、次數。
在真正的瞭解迴圈寫法之前我們先來了解兩個關鍵詞 Iterable
與 iterator
。Iterable
表示多元素數據集合,並且這些元素可以按照順序的進行走訪。Iterator class
提供接口給 iterator
,也就是集合中的各元素對象。
在 Dart 中符合 Iterable
的有 List
、Set
與 Map
,因為都有實現 Iterable
接口。
For
迴圈最基本的 for
迴圈寫法,想必各位如果有碰過程式都不會太陌生。
List<int> nums = [1, 2, 3, 4, 5];
for (var i = 0; i < 5; i++) {
print(nums[i]);
}
我們也可以使用迭代的方式 (Iterable
) 來走訪 List。
List<int> nums = [1, 2, 3, 4, 5];
// 這個寫法與上面例子不一樣的點在於,這裡的 num (iterator) 是真的照順序的進行走訪 nums (iterable)
// 但是上面的寫法是直接透過操作 index 指向想要的目標
for (final num in nums) {
print(num);
}
最後還有一種為 forEach
,可以針對 iterator
執行動作
List<int> nums = [1, 2, 3, 4, 5];
/* 這種寫法跟 js 的 arrow function 很像
nums.forEach((num) => {
print(num);
}); */
nums.forEach(print);
While
與 do-while
while
在執行迴圈之前會先進行條件判斷;do-while
則是先執行一次迴圈中的行為再進行條件判斷。
List<int> nums = [1, 2, 3, 4, 5];
int index1 = 0;
// 先執行條件判斷
while (index1 < nums.length) {
print(nums[index1]);
index1 += 1;
}
int index2 = 0;
// 先執行程式區塊
do {
print(nums[index2]);
index2 += 1;
} while(index2 < nums.length);
Break
與 continue
兩者皆為在迴圈中常用的關鍵字,break
可以跳出當前的迴圈;continue
則是跳到下一輪迴圈的狀態繼續執行。
List<int> nums = [1, 2, 3, 4, 5];
for (var i = 0; i < nums.length; i++) {
if (i == 1) {
// 當 i 為 1 時 continue 跳到下一輪迴圈
continue;
} else if (i == 3) {
// 當 i 為 3 時跳出迴圈
break;
}
// 有成功執行到這裡的只有當 i 為 0 與 2 的時候,所以只會印出 1 3
print(nums[i]);
}
函式是將重複的程式邏輯、動作進行封裝並且可重複呼叫的重要角色。
函式與變數相同有各自的型態,對應於此函式將要回傳值的型態。若該函式無回傳值則宣告為 void
型態。
// 定義一個函數名為 isEmpty 回傳值為 bool 型態,並且傳入參數 nums 為 List<int> 型態
// 此函數用於判斷傳入的陣列是否為空,因此當長度為 0 時則回傳 ture,否則為 false
bool isEmpty(List<int> nums) {
return nums.length == 0;
}
函式的參數是在定義一個函式時需要的變數,像是上述例子的函式中 nums
就是此函式所需要的變數,因此在呼叫函式時需要傳遞相應型態的變數給函式使用。
一個函式可以有無限個參數,並且按照定義的順序來傳遞。但為了讓函式更具彈性,Dart 支援 optional parameters
也就是可以選擇性傳遞的參數,可以以 named parameters
或 optional positional parameters
兩種方法擇一來使用。
當使用 named parameters
時以 {參數1, 參數2, ...}
格式進行定義。若沒有給定參數的預設值或標示 required
時即表示該參數為 nullable
且預設值為 null
。相對來說,若是標示 required
的參數則是在呼叫該函式時必須夾帶該參數才行。
// 此函式定義參數
// - name 有標註 required,表示呼叫此函數時需夾帶 name 參數
// - age 有給預設值,因此呼叫此參數若有給 age 使用夾帶值,否則帶入 0
// - isMale 為 nullable,因此可選擇性夾帶
void addPerson({required String name, int age = 0, bool? isMale}) { ... }
void main() {
// 在呼叫函式時,就可以具名的給定參數
addPerson(name: 'Micro Jordan', age: 25, isMale: true);
addPerson(name: 'Amy', age: 25);
addPerson(name: 'Mike');
}
將參數用 []
包住就可以表示該參數為可選擇性的夾帶,若未給預設值的參數,則表示該參數為 nullable
且預設值為 null
。
// 此函數定義參數
// - name 因為未用 [] 包起來,需擺放在第一個參數位置
// - age 被包在 [] 中因此可選擇性夾帶,因有給預設值所以未使用時預設帶入 0
// - isMale 則可選擇性的夾帶
void addPerson(String name, [int age = 0, bool? isMale]) { ... }
void main() {
addPerson('Micro Jordan', 25, true);
addPerson('Amy', 25);
addPerson('Mike');
}
補充:
main()
函式為整個程式的進入點,當我們在使用該程式時也可以給定執行時的參數,讓程式支援多項指令的功能。
舉例來說:在 linux command 中有提供
ls
這個指令,用於列出當前資料夾底下的檔案結構。若是ls -l
則能列出這些檔案結構各字詳細的資訊、ls -a
可列出隱藏檔等等。這個實現方式便是將-l
、-a
等等的當作執行參數傳入程式中,讓程式進行對應的操作。
void main(List<String> arguments) {
// 參數會以 List of String 的形式傳入程式當中
print(arguments);
}
我們剛剛看到的函式都有明確的名稱,但 Dart 也支援匿名函式,用於簡單的操作上並可讓程式碼更簡潔。匿名函式使用 =>
來定義,我們用例子來說明
// 我們定義了匿名函式 () => ... 並且將 function 指派給 add 變數
var add = (int x, int y) => x + y;
// 因此可執行
print(add(3, 5));
泛型可以讓定義的程式碼能兼容多種型態,也能有效的避免程式碼間只是因為型態不同卻要覆寫很多份的難題。其實我們在目前接觸到的如 List
、 Set
、Map
都是運用到泛型來定義並且實作的。
我們從簡單的例子來看看
// 定義取得傳入 List 的第一個元素
int getFirstItem(List<int> list) {
return list[0];
}
上面的這個例子我們傳入了整數型態的 List,並因為整數 List 中第一個元素一定也是整數,所以再回傳 int
型態,目前為止都沒什麼問題。
但當我們今天需要實現 String
型態的實作方法呢?我們則必須再寫一次一模一樣的程式碼,僅僅只是型態不同而已。
// 再寫一次幾乎一模一樣的程式
String getFirstItem(List<String> list) {
return list[0];
}
因此這時候就可以讓泛型派上用場,當我們在查看 Dart 文件時應該時常看到型態是用 T
、E
等等的單一字母來標註型態,這其實也就是泛行的寫法。由於我們傳入的為單一型態設為T
的 List ,因函式的實作便是回傳 List 中第一個元素,因此回傳型態也為 T
。函式名字後的<T>
則用於標示於該函式中我們定義了 T
這一個泛型。
T getFirstItem<T>(List<T> list) {
return list[0];
}
當今天有多個型態的泛型需要實現時如Map 的定義為 Map<K, V>
,就在<>
多宣告即可。
if
:使用最常見的 if-else
來執行不同條件下的程式。if-case
:透過 if-case
在特定條件下執行程式。switch
:使用 switch
針對單一判斷式進行評估,比對多個 case
,也可設定 default
來執行預設行為。for
迴圈:基本的 for
迴圈,用於指定次數的迭代。while
與 do-while
:while
在迴圈前進行條件判斷,而 do-while
先執行一次迴圈後再進行條件判斷。break
與 continue
:用於控制迴圈的流程,break
可以跳出迴圈,continue
可以跳過目前迴圈的狀態繼續執行下一輪迴圈。named parameters
或 optional positional parameters
兩種方式來定義。T
,可以應用於函式、類別等地方。這提高了程式碼的彈性和重用性。今天介紹的概念我們都從比較簡單的角度進行切入,希望有幫助到大家對於這個語言的初步認識。明天我們會談談類別、錯誤處理相關的內容。明天見囉~