热门问题
时间线
聊天
视角
迴圈
来自维基百科,自由的百科全书
Remove ads
循環是電腦科學運算領域的用語,也是一種常見的控制流程。循環是一段在程式中只出現一次,但可能會連續執行多次的程式碼。循環中的程式碼會執行特定的次數,或者是執行到特定條件成立時結束循環,或者是針對某一集合中的所有項目都執行一次。
在一些函數程式語言(例如Haskell和Scheme)中會使用遞歸或不動點組合子來達到循環的效果,其中尾端遞迴是一種特別的遞歸,很容易轉換為迭代。[1]
指定執行次數的循環(for loop)
大部份程式語言都提供循環的指令,可以依指定的次數重覆執行一段程式。
若指定的次數N小於1,程式語言會忽略整個循環不去執行,若指定的次數N為1,則循環只會執行一次。
在循環進行時,循環計數器也會隨着變化,大部份的程式語言可以允許循環計數器上數或是下數,每次的變化量可以是1或是其他不為0的數值。
FOR I = 1 TO N for I := 1 to N do begin xxx xxx NEXT I end; DO I = 1,N for ( I=1; I<=N; ++I ) { xxx xxx END DO }
在許多程式語言中,循環計數器要使用整數才能得到準確的結果。由於硬件的限制,在循環計數器使用浮點數時,結果可能會不符預期,如以下的循環
for X := 0.1 step 0.1 to 1.0 do
依其四捨五入的誤差、硬件及編譯器的差異,不一定會執行10次,可能只會執行9次。而且X的數值可能會有些誤差,不是預期的0.1, 0.2, 0.3, ..., 1.0。
Remove ads
指定條件的循環(while loop/doWhile loop)
大多數的程式語言都有指令,可以在特定條件成立時繼續循環的進行,或是特定條件不成立時繼續循環的進行,進行到特定條件成立為止。前者一般會標示while,後者一般會標示until。
其判斷條件可能在循環一開始就進行,或是在循環最後才進行。前者的循環不一定會執行,而後者1的循環至少會執行一次。
DO WHILE (test) repeat xxx xxx LOOP until test; while (test) { do xxx xxx } while (test);
Remove ads
指定集合的循環
許多程式語言支援一種特別的循環,可以針對一個陣列中的元素或是一個集合中的所有成員進行循環中的指令,包括Ada、D語言、Smalltalk、Perl、C#、Visual Basic、Ruby、Python、Java、JavaScript、Fortran 95等程式語言都有這類的循環結構:
someCollection do: [:eachElement |xxx]. foreach (item; myCollection) { xxx } foreach someArray { xxx } Collection<String> coll; for (String s : coll) {} foreach (string s in myStringCollection) { xxx } $someCollection | ForEach-Object { $_ } forall ( index = first:last:step... )
泛用循環結構
有些程式語言有泛用循環結構,可以用來表示指定次數或指定條件的循環,像C語言的for指令或是Common Lisp語言中的do指令都是這類的例子,不過為了程式的可讀性考量,在這些程式語言中還是儘量使用一些含義較明確的指令(如while指令)。
無窮循環
無窮循環一般會用在有一段程式需要永遠執行,或是該程式在沒有發生特殊事件(如故障)時需要永遠執行的場合,例如一個事件驅動的程式需要持續執行循環,處理發生的事件,直到用戶結束或中斷程式為止。
若在指定條件的循環中,其判斷條件用到的變量數值永遠不會改變,這種程式錯誤也會使得此循環變成無窮循環。
提早結束整個循環
當使用指定次數的循環查表時,會希望在查到需要的資料時就可以直接結束循環的進行,有些程式語言可以用break
或exit
的指令達到這様的功能,這些指令會結束這個循環,接着會執行循環後面的指令。若此循環在副程式中,也可以用return
中斷循環的進行, 同時離開副程式。
以下是Ada程式語言的一個範例,利用exit ... when...
的方式中提早結束循環。
with Ada.Text IO;
with Ada.Integer Text IO;
procedure Print_Squares is
X : Integer;
begin
Read_Data : loop
Ada.Integer Text IO.Get(X);
exit Read_Data when X = 0;
Ada.Text IO.Put (X * X);
Ada.Text IO.New_Line;
end loop Read_Data;
end Print_Squares;
Python支援一個特別的條件判斷式,可以根據最近使用循環是否曾用break
提早結束而做不同的處理,舉例如下:
for n in set_of_numbers:
if isprime(n):
print "Set contains a prime number"
break
else:
print "Set did not contain any prime numbers"
上例中的else
子句是for
循環的一部份,不是內層if
區塊的一部份。Python語言的for
循環及while
循環都支援else
子句,當循環沒有用break
提早結束時就會執行。
Remove ads
循環的特殊指令
有時在使用循環的程式中會希望在特定情形下跳過目前循環區塊的指令,回到循環開始執行下一個循環,一般這類的指令會命名為continue
、skip
或next
,其效果是提早結束這次循環的進行,繼續進行下一個循環,若此循環已經是最後一次執行,這類指令會結束循環的進行,繼續進行後續的指令。
像Perl及Ruby等程式語言有redo
指令,可以重新執行目前的循環,若在指定次數的循環中,其循環計數器的數值不會變化。Ruby程式語言有retry
指令,可以讓循環計數器回到初值,重新執行整個循環。
循環變式及循環不變式
循環變式是一個初值不為負的整數表示式,在每次執行循環時循環變式的數值需減少,但在正常的循環執行過程中循環變式的數值不會變成負值。循環變式用來確保循環會結束。
循環不變式是一個和循環有關的判斷式,在第一次進入循環之前,循環不變式的值需為真,在後續每一次執行循環時,其值也要為真。當循環正確的結束時,其終止條件和循環不變式都會成立。循環不變式可用來監控在循環進行時,某一指定性質的狀態。
像是Eiffel之類的程式語言本身就有支援循環變式及循環不變式,其他語言可能需要有附加元件才能支援此功能,例如Java就需要配合Java建模語言規範的loop statements (頁面存檔備份,存於互聯網檔案館)才能支援此機能。
不同語言的循環比較表
- a 此項只考慮專用的無窮循環程式結構,因此
while (true)
和for ( ; ; )
都不算在內。 - a b c d e f g h C語言的
for (init; test; increment)
循環是一個通用的循環指令,累加量也不一定要為1。 - a b c 在C、C++及C#中,跳出多層循環可以用label和goto指令達到。
- a 在PHP 5中已支援 (頁面存檔備份,存於互聯網檔案館)配合物件的循環。
- a b c 指定次數的循環可以用重覆incrementing list或generator的方式來達到其效果,例如Python中的
range()
。 - a b c d e 可以用例外處理來跳出多層循環。
- a 沒有專門指令,但
while
指令可以用作此用途。 - a 沒有專門指令,但用戶可以定義通用循環指令。
- a 正在計劃的C++0x標準中已加入以範圍為基礎的 for 循環。標準模板庫(STL)中有
std::for_each
模板函數,可以對STL容器(container)的每個元素重複呼叫一個一元函數[3]。製作STL容器的巨集也可以達到類似的效果[4]。 - a 利用整數區間的迭代可以達到指定次數循環的效果, early exit可以用多增加一個exit的條件來達成。
- a Eiffel支援保留字
retry
,不過是用在契約式設計的異常處理,不是循環的流程控制指令。 - a 需要配合Java建模語言(JML)。
Remove ads
參考資料
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads