for 迴圈電腦程式最重要的工作之一,就是重覆執行相似的工作。例如,假設我們想要知道 1*2*3*4*... *9*10 是多少(也就是 10 的階乘),當然,可以寫成: print(1*2*3*4*5*6*7*8*9*10) 不過,當想要計算的數字變得很大的時候,這樣就不太方便了。而且,如果想要寫一個程式,讓使用者輸入一個數字,就可以計算出它的階乘,就不可能這樣寫了。 在程式語言中,「迴圈」(loop)就是用來進行這種重覆的工作。最簡單的迴圈是 for 迴圈(for loop)。在 Lua 中有兩種不同的 for 迴圈,我們先看第一種: for i = 1,10 do 上面的程式,會印出 1 至 10 之間的數字。 for i = 1, 10 的意思是說,建立一個暫時性的變數 i,它的值從 1 開始,一直加 1 直到 10,重覆執行 do 和 end 之間的程式。所以,一開始 i 的值是 1,執行 print(i),接著 i 的值變成 2,再執行 print(i),依此類推直到 i 的值是 10 為止。因此,上面的程式,會印出 1 至 10 之間的數字。 要把上面的程式改成計算階乘,相當容易: fac = 1 上面的程式,會執行 fac = fac * 1、fac = fac * 2、…、直到 fac = fac * n 為止。因此,fac 變數的值就會是 1*2*3* ... *n 了。 把上面的程式稍微修改一下,使它可以接受使用者的輸入,如下: io.write("n = ? ") 執行這個程式的結果如下: n = ? 10 有關 for 迴圈,還有幾個要注意的地方。首先,它當然不一定要從 1 開始。例如,也可以寫 for i = 10,20 do 它會印出 10 至 20 之間的數字。另外,如果不想要每次是加 1,可以這樣寫: for i = 10,20,2 do 在 10,20 後面的 2 表示每次不是加 1,而是加 2。因此,上面的程式會印出 10、12、14、16、18、20。 同理,如果想要倒過來,可以要求它每次加上 -1。例如: for i = 20,10,-1 do 它會印出 20、19、18、…、11、10。 如果在 for 迴圈中指定的範圍不合理的話,for 迴圈將不會執行。例如: for i = 10,5 do ... end 不會做任何事,因為 10 比 5 大,所以 10 一直加上 1 並不會變成 5。同理: for i = 10,20,-1 do ... end 也不會執行,因為 10 一直加上 -1 並不會達到 20。 不過,下面的迴圈是會執行的: for i = 10, 20, 3 do ... end 此時 i 的值會分別是 10、13、16、19。同樣的: for i = 20, 10, -3 do ... end 也會執行,i 的值會分別是 20、17、14、11。 for 迴圈的注意事項使用 for 迴圈的時候,有幾件事情要特別注意: 首先,for 迴圈所使用的變數(例如前面例子中的 i ) 只是一個暫時的變數。它只在該 for 迴圈中有效,而且在 for 迴圈中不可以修改它的值。例如,下面的程式碼是錯誤的: for i = 1,10 do 像這樣的程式碼,Lua 是不會保證其執行結果的。同樣的,下面的程式碼 i = 100 由於 for 迴圈中使用的 i 只在 for 迴圈中有效,因此,上面的程式中 print(i) 會印出之前 i 的值,也就是 100。 最後一個要注意的地方是,當 for 迴圈的範圍是變數或運算結果的時候,它只會被計算一次。例如,下面的程式碼: n = 10 它仍只會印出 1 至 10 的數字,而不會因為 for 迴圈中修改了 n 的值,使迴圈的執行次數改變。 從迴圈中跳出有時可能會想要中途從迴圈中跳出來。例如,假設我們現在要寫一個程式,可以讓使用者輸出一堆數字,計算出它們的和,和平均值。我們可以這樣寫: io.write("Input n: ") 不過,這樣寫有個缺點:使用者要先知道他有幾個數字要輸入。如果數字很多的話,這可能會相當麻煩。因此,我們可以讓使用者在中途輸入 "end",表示他已經把所有的數字都輸入了。因此,我們會在 for 迴圈中,加入一個判斷式: for i = 1,n do 上面的 if 是一個「判斷式」,表示如果條件成立的話,就執行 then 和 end 之間的指令。在這裡,條件是 a == "end"。Lua 中使用兩個等號 == 表示「相等」。也就是說,這一行指令的意義就是,如果 a 等於 "end" 則執行 break。在迴圈中執行 break,會立刻跳出迴圈的執行。 當然,上面的程式還是不對,因為,如果使用者中途跳出的話,所輸入的數字就不是 n 了。這會使得後面計算平均值的地方錯誤。因此,應該要把 n 設成正確的值: for i = 1,n do 上面的程式中,如果 a 等於 "end"(即使用者要提前結束輸入數字的動作),那麼就把 n 設為 i - 1,也就是目前已經輸入的數字數目。這樣一來,後面計算平均值的時候,就不會出錯了。 最後,還有一個小問題:如果使用者一開始就輸入 "end",而沒有輸入任何數字的話,n 會是 0(因為 i 一開始是 1,而 n = i - 1 = 0)。這樣一來,在計算平均值的時候,會發生除以 0 的情形。如何修改程式,讓 n 是 0 的時候不計算平均值,就讓讀者自行嘗試吧! while 迴圈前面的程式中,使用者一開始還是要輸入一個 n,但是這實在顯得多餘。但是,由於我們不知道使用者會輸入多少數字,所以我們應該使用一個新的迴圈:while 迴圈。我們可以把上面的程式改寫成: io.write("Enter numbers (enter end to quit):\n") 在上面的例子中,while a ~= "end" do ... end 表示,如果 a ~= "end" 成立的話(~= 表示「不等於」的意思)就執行重覆 do ... end 之間的程式。所以,一開始先讀取使用者輸入的數字到 a,如果 a 不是 "end",就執行 sum = sum + a 和 n = n + 1 (計算數字的和,和數字的數目),然後,再讀取下一個使用者輸入的數字,直到 a 是 "end" 才跳出。 和 for 迴圈相同的,while 迴圈也可以透過 break 中途跳出。 repeat 迴圈前面提到的 while 迴圈中,條件是在進入迴圈之前就進行判斷。例如,前面的例子中,如果一開始使用者就輸入 "end",就完全不會進入到迴圈中。 有的時候,我們會希望迴圈至少執行一次以上,這時就會希望條件式是在迴圈的後面進行判斷。例如,假設我們希望前面的程式,改成每次都會顯示輸入的提示字串,以免使用者輸入太多數字後,忘了要輸入什麼字串才能結束程式。如下所示: sum = 0 不過,這樣修改有一個缺點,就是印出提示字串的部份,重覆了兩次。這種情形是在寫程式時,會希望能儘量避免的。除了顯得冗長之外,這也可能會造成一些潛在的問題。例如,假設未來要修改程式的提示字串,就有可能只修改了其中一個,而忘了修改另一個。 要避免程式的重覆,就需要使用到 repeat 迴圈。把程式改成如下: sum = 0 要注意的是,repeat ... until 的條件式,和 while 的條件式剛好相反。while 的條件式是指定迴圈執行的條件(例如上面例子中的 a ~= "end",即表示當 a 不是 "end" 時則繼續執行迴圈),但是 repeat ... until 的條件式則是指令迴圈停止的條件。例如上面的 a == "end" 是指定當 a 是 "end" 時,則結束迴圈。 |
|
Copyright(c) 2007 Ping-Che Chen