iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 12
0
Software Development

Dart 語言 - 開啟 Flutter 的鑰匙系列 第 12

Day 12:控制流程語句 (Control flow statements)

程式語言的執行順序一般都是由上往下,逐行執行。不過有一些語句,可以改變執行的流程,我們稱之為「控制流程語句 (Control flow statement)」

if-else

將條件 (bool) 置入If 中,當條件成立,則執行 if 語句,否則執行 else。

var state = true;
if(state){
	print('state is true');
}else{
	print('state is false');
}

if- else if - else

還可以在if-else 中間插入其他的判斷條件,用 else if 關鍵字做判斷。

var point = 10;

if(ponint < 10){
	print('point is less than 10');
}else if(point < 50){
	print('point is less than 50');
}else{
	print('point is $point');
}

但是,避免使用 else if。

如果有多個條件,請使用 switch。


for 迴圈

用 for 可以依序走訪列表的每一個元素。

var list = ['Tiger', 'Lion', 'Eagle'];

for(var i=0; i<list.length; i++){
    print(list[i]);
}

發現什麼?

在 for 迴圈中,開始與結束的數值都可以自己調整。

for-in

若是 Iterable 類的子類別,如 List,Set...

如果需要走訪每一個元素,可以使用 for-in 迴圈:

所以可以將上例改為:

var list = ['Tiger', 'Lion', 'Eagle'];
for(var item in list){
    print(item);
}

發現什麼?

for-in 迴圈不需要指定開始與結束的位置,它只是將集合類裡面的每一個元素依序列出。

所以 for 迴圈每一次都會產生新的索引值,而 for-in 迴圈,每一次都會產生一個集合類裡面的元素。

for 迴圈的陷阱

Dart 中,集合函數的索引值是由 0 開始計算,所以最大值會是 list.length -1。

但是在 for 迴圈中,開始與結束的位置是自己定義的,若是超出集合類的大小,就會發生錯誤。

例如:某工程師將 List 的索引值記成由 1 開始,那麼,他有可能會寫出底下的程式。

當 i 的值到 3 時,因為list[3] 是不合法的,所以會發生錯誤。

var list = ['Tiger', 'Lion', 'Eagle'];

for(var i=1, i<=list.length; i++){
    print(list[i]);
}

while/do-while

while 迴圈

當條件成立,則會持續在 while 迴圈裡執行。

var i = 0;
while(i<=10){
	print(i);
	i++;
}
//0
//1
//2
//3
//4
//5
//6
//7
//8
//9
//10

do-while 迴圈

會先執行一次,接者才會執行 while 迴圈。

var state = false;
do{
	print('state is $state');
}while(state);
//state is false
  • 上例,因為 state 為 false,while 迴圈不會執行,所以只會執行 do {} 裡的運算式一次。

break

在 while 迴圈中,一般都是等到條件不成立之後,才可以跳出迴圈。

但是,利用關鍵字 break ,可以直接跳出迴圈,而不需等到條件不成立。

var i = 0;
while(i<=10){
	print(i);
	i++;
	if(i == 4) break;
}
//0
//1
//2
//3

同樣的,我們也可以把 break 用在 for 迴圈上。

var list = ['Tiger', 'Lion', 'Eagle'];

for(var i=0, i<list.length; i++){
    print(list[i]);
		if(list[i]=='Lion') break;
}

//Tiger
//Lion

continue

關鍵字 break 是將跳出迴圈,如果我們想要繼續完成迴圈,但是某些迴圈的條件我們不考慮呢?

利用關鍵字 contiune 可以跳到迴圈的下一次進行。

for(var i=0; i<10; i++){
	if(i%2 == 1) continue;
	print(i);
}
//0
//2
//4
//6
//8
  • 上面範例,我們想列印出 0~9 中,偶數的部分。我們將每一次迴圈得到的 i 做餘數計算,餘數為 1 ,表示該數字為奇數,利用後方的 continue 關鍵字繼續下一次迴圈,所以下一行的 print(i) 就不會被執行到。

  • 當然 continue 也可以用在 while 迴圈內。

switch / case

在 for 迴圈的介紹裡,我們提到應避免使用 else if ,要使用 switch 。

var sport = 'baseball';
switch (sport){
  case 'baseball':
		playBaseball();
    break;

  case 'basketball':
		playBasketball();
		break;

	default:
		print('$sport is not ready');
		break;
}
  • switch / case 可以比較有條理的分離每一個條件。具有較高的在程式可讀性。

同樣的範例,我們用 if - else if - else 來改寫

var sport = 'baseball';

if(sport == 'baseball'){
	playBaseball();
} else if(sport == 'basketball'){
	playBasketball();
}else{
	print('$sport is not ready');
}

發現什麼?

我們要判斷 sport ,在每一個 if/else if 裡,我們都會看到 sport == 的程式碼,這會造成多餘的 code。

enum

enum 是一種型別,用於自定義 type,若用在 switch 上,IDE 會自動告訴我們有哪一個 enum 尚未考慮到。

  • 如何定義 enum?

用關鍵字 enum 加上 enum 名稱,用大括弧定義所有的情況。

範例:有一個 enum 型別,名稱為 NetworkState。我們定義三種情況:1. online,2. offline, 3. airplane_mode。

enum NetworkState{online, offline, airplane_mode}
  • 如何使用 switch case 搭配 enum
void checkNetworkState(NetworkState networkState){

  switch(networkState){
		case online:
			print('Online');
			break;
		case offline:
			print('Offline');
			break;
		case airplane_mode;
			print('Airplane Mode');
			break;
  }

}

承上所述,用 switch case 判斷 enum 值,若 switch case 裡的數量與 enum 數量不符合時,IDE 會跳出警告,讓我們可以注意補上漏掉的 case。

例如:上面的範例,我們少寫了 airplane_mode

void checkNetworkState(NetworkState networkState){
  switch(networkState){
    case NetworkState.online:
      break;

    case NetworkState.offline:
      break;
  }
}

→ 結果 IDE 就跳出警告通知我。

switch-enum-warning

default

在 switch 中,除了可以用 case 定義每一個情況所要執行的運算式,還可以把剩下沒定義的用關鍵字 default 定義。

例如:上面少一個 case 的範例,我們可以用 default 補上。

void checkNetworkState(NetworkState networkState){
  switch(networkState){
    case NetworkState.online:
      break;

    case NetworkState.offline:
      break;

	default:
	  break;
  }
}

switch case 的陷阱

當使用 switch case 時,必須要注意是否每一個 case 都有相對應的 break;。

當定義 case 卻沒有 break; ,此時在此 case 底下的 case 就會被呼叫到。

如下:有名工程師,將 case online:break; 忘了寫。

void checkNetworkState(NetworkState networkState){

  switch(networkState){
		case online:
			print('Online');
		case offline:
			print('Offline');
			break;
		case airplane_mode;
			print('Airplane Mode');
			break;
  }

}

void main(){
	checkNetworkState(NetworkState.online);
}
//Online
//Offline
  • 當呼叫 checkNetworkState 帶入 NetworkState.online 時,除了自己本身的運算式,連帶下一個運算式也被呼叫了。

switch 補充

除了關鍵字 break 可以跳出 switch 之外,關鍵字 continuethrow 或是 return 都可以跳出 switch。


assert

在開發中,我們有可能會需要確定某些地方的值是否如我們預期,我們可以用關鍵字 assert

例如:我們希望該函數 showName 沒有空值傳進來,我們可以在函數裡面加上 assert,當在 debug 模式發生傳入 showName 的值為空時,此時就會發生錯誤。

void showName(String name){
	assert(name !=null );
	print('$name')
}

小結

幾乎所有程式語言都有控制流程語句,它也是基本程式語言的基本功夫之一。但是,越容易的東西,越容易誤用,越用越糟。

如引言所述,程式語言是依序執行,如果控制流程語句用得太多,執行順序也會因此改變很多,那麼維護的時候就會變得很不容易。

if-else, switch 算是條件判斷類,一定要把每一個條件都判斷清楚,才不會有遺漏的情況,造成誤動作。所以判斷兩個情況,建議使用 if-else,多個情況可以使用 switch 搭配 enum。

使用 for 迴圈時,一定要注意迴圈的起始值,如果是迭代類 (iterable), 建議使用 for-in 迴圈,或是forEach 函數。

最後是 while,使用 while 一定要注意條件有沒有辦法變成不成立,否則無窮迴圈就會等著你。


上一篇
Day11:運算子 (下) - Operators
下一篇
Day 13:例外處理
系列文
Dart 語言 - 開啟 Flutter 的鑰匙30

尚未有邦友留言

立即登入留言