回圈

回圈是计算机科学运算领域的用语，也是一种常见的控制流程。回圈是一段在程式中只出现一次，但可能会连续执行多次的程式码。回圈中的程式码会执行特定的次数，或者是执行到特定条件成立时结束回圈，或者是针对某一集合中的所有项目都执行一次。
在一些函数程式语言（例如Haskell和Scheme）中会使用递归或不动点组合子来达到回圈的效果，其中尾部递归是一种特别的递归，很容易转换为迭代。

**指定执行次数的回圈(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
for X := 0.1 step 0.1 to 1.0 do
依其四舍五入的误差、硬体及编译器的差异，不一定会执行10次，可能只会执行9次。而且X的数值可能会有些误差，不是预期的0.1, 0.2, 0.3, ..., 1.0。

**指定条件的回圈(while loop/doWhile loop)**
大多数的程式语言都有指令，可以在特定条件成立时继续回圈的进行，或是特定条件不成立时继续回圈的进行，进行到特定条件成立为止。前者一般会标示while，后者一般会标示until。
其判断条件可能在回圈一开始就进行，或是在回圈最后才进行。前者的回圈不一定会执行，而后者1的回圈至少会执行一次。
DO WHILE (test)           repeat 
xxx                       xxx 
LOOP                      until test;

while (test) {            do
xxx                       xxx
}                         while (test);

**指定集合的回圈**
许多程式语言支援一种特别的回圈，可以针对一个阵列中的元素或是一个集合中的所有成员进行回圈中的指令，包括Ada、D语言、Smalltalk、Perl、C#、Visual Basic、Ruby、Python、Java、JavaScript、Fortran 95等程式语言都有这类的回圈结构：
someCollection do: xxx.

foreach (item; myCollection) { xxx }

foreach someArray { xxx }

Collection 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提早结束时就会执行。

**回圈的特殊指令**
有时在使用回圈的程式中会希望在特定情形下跳过目前回圈区块的指令，回到回圈开始执行下一个回圈，一般这类的指令会命名为continue、skip或next，其效果是提早结束这次回圈的进行，继续进行下一个回圈，若此回圈已经是最后一次执行，这类指令会结束回圈的进行，继续进行后续的指令。
像Perl及Ruby等程式语言有redo指令，可以重新执行目前的回圈，若在指定次数的回圈中，其回圈计数器的数值不会变化。Ruby程式语言有retry指令，可以让回圈计数器回到初值，重新执行整个回圈。

**回圈变式及回圈不变式**
及回圈不变式是判断回圈正确性的工具。
回圈变式是一个初值不为负的整数表示式，在每次执行回圈时回圈变式的数值需减少，但在正常的回圈执行过程中回圈变式的数值不会变成负值。回圈变式用来确保回圈会结束。
回圈不变式是一个和回圈有关的判断式，在第一次进入回圈之前，回圈不变式的值需为真，在后续每一次执行回圈时，其值也要为真。当回圈正确的结束时，其终止条件和回圈不变式都会成立。回圈不变式可用来监控在回圈进行时，某一指定性质的状态。
像是Eiffel之类的程式语言本身就有支援回圈变式及回圈不变式，其他语言可能需要有附加元件才能支持此功能，例如Java就需要配合Java Modeling Language规范的 loop statements date=20200717141600 才能支持此机能。

**不同语言的回圈比较表**
# a 此项只考虑专用的无穷回圈程式结构，因此while (true)和for ( ; ; )都不算在内。
# aceg C语言的for (init; test; increment)回圈是一个通用的回圈指令，累加量也不一定要为1。
# ac在C、C++及C#中，跳出多层回圈可以用label和goto指令达到。
# a 在PHP 5中已 支援 date=20210518224709 配合物件的回圈。
# ac 指定次数的回圈可以用重复incrementing list或generator的方式来达到其效果，例如Python中的range()。
# ace 可以用异常处理来跳出多层回圈。
# a 没有专门指令，但while指令可以用作此用途。
# a 没有专门指令，但使用者可以定义通用回圈指令。
# a 正在计划的C++0x标准中已加入以范围为基础的 for 回圈。标准模板库（STL）中有std::for_each模板函数，可以对STL容器（container）的每个元素重复呼叫一个一元函数。制作STL容器的巨集也可以达到类似的效果。
# a 利用整数区间的迭代可以达到指定次数回圈的效果， early exit可以用多增加一个exit的条件来达成。
# a Eiffel支援保留字retry，不过是用在契约式设计的异常处理，不是回圈的流程控制指令。
# a 需要配合Java Modeling Language（JML）。