Chapter 16. 控制迴圈

16.1 選擇迴圈種類

  • 計數迴圈(counted loop):執行的次數是一定的
  • 連續求值的迴圈(continuously evaluated loop):預先並不知道將要執行多少次,但每次迭代前會檢查是否該結束了。
  • 無限迴圈(endless loop)
  • 迭代器迴圈(iterator loop):對容器類裡面的每個元素執行一次操作

迴圈的使用時機

不知道要用迭代多少次的時候 -> while 有固定次數 -> for 在某個特定容器內 -> foreach

帶結束迴圈

帶結束迴圈指的是終止條件出現在迴圈中間。


while (true){

  if ( some condition ) break

}

16.2 迴圈控制

迴圈會出的錯誤:

  • 錯誤地對迴圈執行初始化
  • 忽略了累加變數或其他與迴圈有關變數的初始化
  • 不正確的巢狀結構
  • 不正確的迴圈終止
  • 錯誤地增加了迴圈變數的值
  • 用不正確的迴圈所引來存取陣列元素

把你的迴圈當作function看待 你不必知道迴圈裡面做了什麼,但你會明確的知道迴圈進行的條件是什麼。 (你不一定了解 function 內部的實作細節,但是會知道 function 的名稱、參數、回傳值等)

進入迴圈 Tips

  • 把初始化的程式碼緊放在迴圈的前面
  • 用 while(true) 代表無限迴圈
  • 大多數情況下使用 for (因為 while 迴圈有終止條件,你有可能忘記他寫在哪了。)
  • 當使用情境更適合使用 while 時就別使用 for
  • 避免使用空迴圈
  • 一個迴圈只做一件事

結束迴圈 Tips

  • 確認迴圈是能夠結束的
  • 讓迴圈終止的條件看起來很明顯
  • 不要為了終止迴圈而胡亂更改 for 迴圈的索引
  • 避免出現依賴於迴圈索引最終曲直的程式碼
for (recordCount = 0; recordCount < MAX_RECORDS; recordCount ++){
  if(some condition){
    ...
  }
}

// ...

if(recordCount < MAX_RECORDS){
  return (true)
}
else{
  return (false)
}

// 真的有人會這樣用嗎?
  • 考慮使用安全計數器 - 提供一個變數為計數器,每次迴圈開始都去檢查計數器。
  • 小心那些有很多 break 散佈其中的迴圈
  • 在迴圈開始處使用 continue 進行判斷
  • 如果語言支援的話使用帶標籤的 break

端點、索引(index) Tips

  • 確認好端點以防 off-by-one 的問題
  • 用整數或 enum 來表示迴圈的邊界
  • 在巢狀迴圈中使用有意義的變數來提高可讀性
  • 用有意義的名字來避免巢狀中的索引互相干擾
  • 把索引變數的作用範圍限制在迴圈內

迴圈應該多長

  • 盡可能地短
  • 巢狀限制在 3 層以內
  • 把長程式移動到子程式內