迴圈也是程設設計中不可或缺的 statement,寫程式很多時候就是要幫我們做掉一些重複無意義的動作(可是偏偏很多 User 喜歡做這些事情...XD),從 for-loop,while-loop, do-until...每一種語言都有自己的迴圈控制器,不過寫法大同小異。
最怕也最常發生的就是,產生無窮迴圈。例如:
do while not rs.eof
a=rs.fields(0).value
loop
少寫了一個 rs.movenext() 結果程式進入無窮迴圈,只好 CTRL+ALT+DEL。可以 break 掉的還好,最怕是 run 在 console 的程式,一 run 的結果,整個 server 都 hang 住,那就糗大了!還好 VB.Net 改採 Data Reader 的方式,
do while dr.read()
...
loop
這樣就不會有無窮迴圈問題的發生,當然這只是一種情況,還有很多因為變數的控制問題,導致迴圈運作不正常。所以,以下就介紹幾個寫迴圈時,該注意的地方。
.將初始化的程式碼放在靠近迴圈的地方
將初始化的動作放在迴圈的起始處集中處理,對程式維護與閱讀上會比較方便,也不會漏掉修改而導致錯誤產生。
.保持迴圈的完整結構
有時候為了節省程式碼,可能一行的指令就可以執行完一個迴圈的動作,如:while(!rs.eof) i++; 也許寫起來很方便,但是常會造成程式撰寫時判斷上的錯誤,所以還是將完整的迴圈結構寫好,反正也不會影響執行的效率,又可避免掉可能發生錯誤的風險,何樂而不為?
.避免空迴圈
寫 console 程式時,可能需要等待按鍵而採用空迴圈讓程式 waiting,如:
while ( (InputChar = getch()) != '\n' );
這樣對程式的閱讀上,比較不好懂,如果改寫成以下情況
do
InputChar = getch();
while ( InputChar != '\n' )
這樣就會比較好辨識,程式所要做的事情。
.避免依賴迴圈變數結束後的值
很多時候,我們常會使用迴圈執行後的變數值,例如 for i=1 to n,我們在後面會認為迴圈執行完後的值為 n+1,所以就直接拿 i 來使用。可是錯誤也常會出現在這邊,如果程式中有離開迴圈的情況,這樣就可能與我們之前所設想的情況會不一樣,而導致錯誤。
如書中的例子:
for (i=0;i<MaxRecords;i++)
{
if (Entry[i]==TestValue)
{
break;
}
}
if (i<MaxRecords)
return (TRUE);
else
return (FALSE);
我們無從判定目前的 i 的值會是多少,所以導致回傳的值可能會出現錯誤,如果改成
Found=FALSE;
for (i=0;i<MaxRecords;i++)
{
if (Entry[i]==TestValue)
{
Found=TRUE;
break;
}
}
return (Found);
這樣是不是就清楚許多!
.使用安全計數器
使用安全計數是避免無窮迴圈導致無法控制的好方法,如果我們預測迴圈應該執行的次數,就可以安排一個安全計數器進入迴圈,如果迴圈執行次數超過這個安全計數器的值,就強迫離開迴圈,這樣就不會有無窮迴圈的狀況產生了。
.審慎使用 goto 與 continue
在 VB6 的年代,因為沒有 continue 這個指令,所以在迴圈中如果減少迴圈次數,就要使用到 goto,如:
do while not rs.eof
if NotExpected then goto Continue
...
Continue:
rs.movenext
loop
如果非得使用 goto 請將 continue 的地方放在離迴圈結束最靠近的地方,這樣比較不會出錯。當然用一個 if-then-else Block 也可以做到上述的情況,不一定要使用 goto 來完成。
如果程式語言有提供 continue,那麼將 continue 的情況寫在愈前面,會讓程式的執行效能愈好。例如:
do while not eof(File)
read(Record, File)
if (Record.type<>TargetType) then
continue
....
loop
如果是在迴圈的結尾的地方才出現 continue,那不如就不用了。
另外就是前面已經提過的,為迴圈的變數採用有意義的命名,這樣可以讓程式比較容易閱讀與瞭解。
現學現練習
請老師評分
<pre class="c" name="code">
do
改規格
喝咖啡
改程式
吃泡麵
自己測程式
睡覺
使用者測程式
聽使用者抱怨
until 驗收 or 離職
do 的內容
少了看圖片(誤)...少了自言自語、自 high...XD
蟹老闆一定給 100 分
章魚哥:我還是去睡覺吧
派大星...已經睡著了...XD
還有上ithelp。
如果有iterator可以用,拿來代替迴圈也不錯。或是像ruby的each這類的方法(下一版的javascript陣列也加了forEach方法),都可以避開使用迴圈。不過也許內部實作還是用迴圈實現的也說不定...