#

迴圈命令可以讓某些程式碼有條件的反覆執行,如果你想讓程式擁有「如果某件事是真的,就反覆做某些事」的功能,這時就要仰賴迴圈命令了。例如,寫一個讀取檔案的程式,你可能會一次從檔案內讀取一部份的內容,然後一直反覆直到讀完檔案。像這樣的情況就會用到迴圈,因為你需要「反覆的讀取,直到讀完整個檔案」。這篇文章會簡單的介紹與迴圈相關的命令。

7.1 while迴圈命令

while是最單純的迴圈命令,常被用來執行不確定次數的迴圈,當然這並不是硬性的規定,真正該如何使用還是得看個人的使用習慣,while的語法如下:

while test body

while命令判斷條件式test的值來決定是否反覆執行body。test是條件式用來決定是否繼續執行迴圈。body是條件式為真的時候要執行的程式碼。while的運作流程如下:

step1 : 直譯器執行到while命令。
step2 : 如果需要的話先處理test及body的代換動作。
step3 : 運算條件式test, 如果執行結果是「真」就執行step4,否則就跳到step5。
step4 : 執行body的內容,執行完跳回step3。
step5 : 結束while迴圈。

§ 關於迴圈條件式

Tcl使用與expr相同的方式來運算迴圈的條件式。換句話說,你可以想像迴圈的條件式,會交由expr命令運算,然後再由運算的結果來判斷迴圈是否反覆執行。

下方是一個非常簡單的例子,透過while命令產出10個按鈕,每按下其中一個按鈕就會印出對應的數字,執行後的結果如下:

圖7-1 用while產生10個按鈕

程式碼如下:

程式的第2行設定while的條件式為「當變數i的值小於10」就執行後面大括號裡的程式,所以只要是i的值小於10程式3~5行就會反覆執行。 接下來請看到第5行,incr命令每執行一次就會把變數i的值加1,也就是說迴圈每執行一次i的值就會加1,所以執行完10次的迴圈i的值將會變為10,這樣會剛好會讓第2行的$i<10判斷為不成立,然後跳出迴圈。像這樣在迴圈裡改變條件式中的變數是很重要的技巧,只要學會控制好裡頭的變數,你就可以隨心所欲的控制迴圈了。 然後請看到第3及第4行,根據代換的規則第3行中的三個$i及第4行中的一個$i都會被代換掉。由於第5行每執行一次i的值都會加1,所以不用擔心button會出現相同的元件ID。注意!! i的值等於10的時候迴圈即會結束,換句話說第3行只會產生.btn0~.btn9,然後跳開迴圈。 接下來讓我們再來看一個讀檔案的例子,下方的程式可以讓使用者選擇一個檔案,並且把所選中檔案的內容全部輸出,程式碼如下:

請把焦點放在第2~9行。第2行的tk_getOpenFile會呼叫出選擇檔案的對話方塊,然後把選中的檔案路徑儲存在變數f裡。第3行判斷使用者是否有選擇檔案,若有的話才執行4~8行。

程式的第4行以讀取模式開啟剛才選中的檔案,然後把控制檔案的代碼儲存在fd變數裡。第5行的while條件式會判斷檔案是否讀取完畢,如果還沒就反覆的執行讀取檔案的動作,一直到讀取完畢才跳開迴圈。最後程式的第8行把讀完的檔案關起來,以免佔用資源。

關於檔案I/O的操作,後面的章節會有較詳細的說明,目前我們只要知道第5行的eof命令可以用來判斷檔案是否已經讀取完畢,若是的話就回傳「真」,否則回傳「假」。而「!」可以用來把真假值反相。所以整個迴圈條件式的意義就是「如果檔案還沒有讀到結尾,就繼續執行迴圈」。另外第6行的gets命令可以一次讀取一行檔案裡的內容,而讀取到的內容被我們用puts命令輸出顯示。

§ 關於檔案操作

檔案操作在以後的章節會更詳細的說明,看不懂的話請不要太在意。讀檔案是個很常見的動作,正常的情況下還沒有讀取之前,我們不容易知道它總共有多少行,上方的程式示範了while在不確定迴圈數的使用時機,這個例子裡不管檔案有多少行都會被正確的讀出。

特別注意!!下方的程式範例會造成迴圈永遠不會結束的無窮迴圈,請小心的避開它。

上方程式的第2行使用了雙引號包夾迴圈條件,根據代換規則$i會在while執行前先被代換為0,相當於如下的程式,不管變數i的值如何改變都不會影響到while的迴圈條件,而造成不會停止的無窮迴圈。

7.2 for迴圈命令

for迴圈是語法比較複雜一點的命令,但拿來執已知次數的迴圈非常的好用,它的語法如下:
for start test next body
start在for命令執行時會無條件先執行一次的程式碼。
test迴圈的條件式用來決定body是否執行。
next每次執行完body命令時會緊接著執行一次的程式碼。
body當條件式test為「真」時要被執行的程式碼。
當for命令開始執行時start會無條件先執行一次,目的是用來初始化迴圈變數。接下來for命令判斷條件式test,如果結果是邏輯的「真」就依序執行body及next,否則結束迴圈。然後就一直重覆著判斷條件式,然後執行body及next的動作,一直到條件式為假才結束迴圈。其中next的目的是用來設定迴圈變數的增量。for迴圈的運作流程可以看成這樣:
step1 : 程式執行到for命令。 step2 : 視情況先處理start、test、next、body的代換動作。 step3 : 無條件執行一次start中的程式碼。 step4 : 運算條件式test。如果結果為「真」跳到step5,否執跳到step6。 step5 : 依序執行body(先)及next(後)的內容,執行完成跳回step4。 step6 : for命令執行結束。
下面的程式用了很笨的方法來計算1加到100,但用來展示for迴圈的用法還滿適合的。 程式的第1行建立了一個變數sum並設定初值是0,我們用它來儲存1累加到100的結果。第2行的start程式碼建立了初值為1的變數i,迴圈的條件test設定為「i的值在小於等於100」時都要執行body及next程式區塊。第3行body程式區塊內,使用incr命令把i的值累加到sum變數裡,next程式區塊則在每次sum累加完成後把i累加1。最後程式的第5行把累加後的結果顯示出來。 在這個程式裡body程式區塊總共會執行100次,i的值會對應目前正執行到第幾次,每次迴圈執行incr會不斷的把i的值累加到sum裡面。

7.3 foreach迴圈命令

foreach是專為清單設計的迴圈命令,它可以讓你很方便的逐一處理清單中的項目,其語法如下:
foreach varName list body
foreach將清單list中的項目值逐一取出,並設定給varName指定的變數,每設定一次varName指定的變數,就緊接著執行一次body程式碼。如下是一個簡單的示範:

這個程式的第1行建立一個9個項目的清單,每個項目都代表一個方位。第2行中list1的項目會逐一設定給變數item,而且每設定一次item第3行就跟著被執行一次。label命令可以用來建立文字標籤,它的-anchor參數可以用來指定文字標籤內部對齊的方位,-bd用來指定邊框大小,-relief用來指定邊框的樣式。程式執行的畫面如下:

圖7-2 程式執行畫面

7.4 break及continue命令

break及continue命令都可以用來改變迴圈執行的流程,它們通常出現在while、for或foreach等迴圈命令的body程式區塊內。如果在body內遇到break命令,break命令會強迫結束目前執行中的迴圈命令。如果在body內遇到continue那麼程式會當做目前一圈的迴圈已執行完成,然後繼續執行下一次圈的動作。如下是break命令的範例:

程式的第2行使用if命令讓變數i的值為5的時候執行break,遇到break程式會立刻跳出迴圈由第5行繼續執行。它的執行結果如下:
0
1
2
3
4
迴圈結束
以下是continue的使用範例:

程式的第2行if命令會讓item值為banana的時候跳過第3行程式。換句話說只要item值為banana時第3行都不會被執行。它的執行結果如下:

apple
bery
tomato
cherry

7.4 本章回顧

迴圈命令可以讓某些程式碼有條件的反覆執行,而Tcl提供了for、foreach及while等3個迴圈命令,其中for常用來執行已知次數的迴圈,while常用來執行未知次數的迴圈,foreach則是專門用來串繞清單的迴圈,它們的語法如下:

while test body

說明:

step1 : 直譯器執行到while命令。
step2 : 如果需要的話先處理test及body的代換動作。
step3 : 運算條件式test, 如果執行結果是「真」就執行step4,否則就跳到step5。
step4 : 執行body的內容,執行完跳回step3。
step5 : 結束while迴圈。

產生10個按鈕的使用範例:

for start test next body
說明:
step1 : 程式執行到for命令。 step2 : 視情況先處理start、test、next、body的代換動作。 step3 : 無條件執行一次start中的程式碼。 step4 : 運算條件式test。如果結果為「真」跳到step5,否執跳到step6。 step5 : 依序執行body(先)及next(後)的內容,執行完成跳回step4。 step6 : for命令執行結束。
計算1加到100的笨方法:
foreach varName list body
說明: foreach將清單list中的項目值逐一取出,並設定給varName指定的變數,每設定一次varName指定的變數,就緊接著執行一次body程式碼。 使用範例:

break及continue命令可以用來改變迴圈執行的流程,如果在迴圈的body內遇到break命令,break命令會強迫結束目前執行中的迴圈命令,如果在迴圈的body內遇到continue那麼程式會當做目前一圈的迴圈已執行完成,然後繼續執行下一次圈的動作。

Theme Design by devolux.org. Converted by Wordpress To Blogger for WP Blogger Themes. Sponsored by iBlogtoBlog
This template is brought to you by : allblogtools.com | Blogger Templates