四種迴圈:for / while / repeat / for-in
先參考下方範例,我們修改前一堂課的程式檔案 mydemo.dpr,將副檔名改成 pas,即 mydemo.pas。這是 Pascal 原始檔的標準副檔名。接下來下載 Notepad++ 等支援語法上色的程式編輯器,能讓程式碼閱讀起來更清晰易懂。
下方是完整可執行範例,每一行程式都加上詳細註解,看完範例後我們會逐行拆解解釋每一段語法。
// 2.8 迴圈敘述:for、while、repeat、for..in
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
// FPC 編譯器指令:開啟物件導向模式、長字串、關閉字串自動參考計數
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
// Windows 平台:指定程式為主控台應用程式(無圖形視窗介面)
{$R+} // 開啟邊界檢查,偵測陣列索引溢位錯誤非常實用
var
MyArray: array [0..9] of Integer; // 整數陣列,共10個元素,索引範圍0~9
I: Integer; // 迴圈計數變數
begin
// 1. 正向 for 迴圈:初始化陣列,存入0到9各自的平方值
for I := 0 to 9 do
MyArray[I] := I * I;
// 2. 基礎 for 迴圈走訪陣列索引,列印平方結果
for I := 0 to 9 do
WriteLn('平方值為 ', MyArray[I]);
// 3. Low/High 自動取得陣列上下界,不用手動寫死0與9,擴充性更佳
for I := Low(MyArray) to High(MyArray) do
WriteLn('平方值為 ', MyArray[I]);
// 4. while 迴圈:先判斷條件,條件成立才執行迴圈本體
I := 0;
while I < 10 do
begin
WriteLn('平方值為 ', MyArray[I]);
I := I + 1; // 三種等價寫法:I+=1 / Inc(I)
end;
// 5. repeat-until 迴圈:先執行一次本體,於結尾判斷離開條件
I := 0;
repeat
WriteLn('平方值為 ', MyArray[I]);
Inc(I); // 計數器遞增
until I = 10;
// 6. for-in 走訪:直接取出陣列內元素數值,不需操作索引
for I in MyArray do
WriteLn('平方值為 ', I);
end.Code language: Delphi (delphi)
以下是移除所有註解後的純程式碼
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}
var
MyArray: array [0..9] of Integer;
I: Integer;
begin
for I := 0 to 9 do
MyArray[I] := I * I;
for I := 0 to 9 do
WriteLn('平方值為 ', MyArray[I]);
for I := Low(MyArray) to High(MyArray) do
WriteLn('平方值為 ', MyArray[I]);
I := 0;
while I < 10 do
begin
WriteLn('平方值為 ', MyArray[I]);
I := I + 1;
end;
I := 0;
repeat
WriteLn('平方值為 ', MyArray[I]);
Inc(I);
until I = 10;
for I in MyArray do
WriteLn('平方值為 ', I);
end.Code language: Delphi (delphi)
接下來我們逐段解析每一種迴圈的程式邏輯
for 迴圈
使用 for 迴圈對陣列賦值
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}
var
MyArray: array [0..9] of Integer;
I: Integer;
begin
for I := 0 to 9 do
MyArray[I] := I * I;
end.Code language: Delphi (delphi)
這段程式分為三個區塊:頂部是前置編譯指令,中間 var 區段宣告變數(一個陣列、一個整數變數),主執行區塊位於 begin 與 end. 之間,內含一組 for 迴圈,將0至9依序指派給變數 I,透過索引填入陣列元素。
對 MyArray[0] 到 MyArray[9] 共十個陣列元素逐一賦值,星號 * 代表乘法運算子,效果等同下方手動指派。
MyArray[0] := 0 * 0;
MyArray[1] := 1 * 1;
…
MyArray[9] := 9 * 9;
接著在第一個 for 迴圈下方新增另一組 for 迴圈,讀取陣列中每一個儲存的數值。

編譯執行後,主控台會輸出所有陣列內儲存的平方值

輸出結果全部為0到9的平方,與我們前面預期的邏輯完全吻合。
若不清楚陣列的索引上下限,可透過內建函式自動取得邊界數值。

上方 Low(陣列名稱) 用來取得陣列最小索引值
Low(型別/變數):取得序數型別、陣列、集合的最小值 / 下界High(型別/變數):取得序數型別、陣列、集合的最大值 / 上界
while 與 repeat 迴圈

在 while 內層 begin end; 包圍的迴圈本體中,變數 I 會在區塊末尾加1;遞增完畢後程式流程跳回 while I < 10 do 重新判斷條件。條件成立則再次執行迴圈、I 再次遞增,持續循環直到 I < 10 不成立才結束整個 while 迴圈,也就是 I 等於10時離開。


while 與 repeat-until 核心差異
- 判斷邏輯相反
while 條件 do:條件成立 → 繼續迴圈;條件不成立 → 離開repeat ... until 條件:條件成立 → 離開;條件不成立 → 繼續迴圈
- 保證執行次數不同
- while:初始條件不滿足時,迴圈完全不會執行
- repeat-until:無論條件真假,至少執行一次迴圈本體
若學過 C、C++、Java 等程式語言,就能快速理解:repeat until 功能等同 do while。先執行一次迴圈內容,再判斷 until 後的條件;條件不成立就持續重複執行。
repeat until 不需要搭配 begin end,repeat 與 until 本身就構成完整程式區塊。雖然可以手動加上 begin end,但建議省略不寫。
repeat until 字面意思就是「重複執行…直到條件成立」,從英文單字就能直觀理解用途。

走訪過程會依序把 MyArray 內每個數值指派給 I,直接操作 I 即可,不需手動遞增索引,甚至完全不用索引變數,直到全部元素走訪完畢。
一般 for 迴圈(for I := ... to/downto)說明
- 對應 C 語言 for 迴圈,但限制更嚴格:僅能走訪連續序數(整數、列舉型別);
- 支援 downto 反向走訪:
for I := 9 downto 0 do; - 上下界
Low(變數)/High(變數)僅在迴圈開頭計算一次,執行效率高; - 迴圈正常結束後,變數 I 數值未定義,編譯器會拋出警告;若透過
Break/Exit提前中斷迴圈,I 會保留當前數值。
for-in 走訪(現代 foreach 風格)
可直接走訪四類資料,不用手動操作索引:
- 陣列:直接讀取每個元素數值(前面範例已示範)
- 列舉型別
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}
type TAnimalKind = (Duck,Cat,Dog);
var AK:TAnimalKind;
begin
for AK in TAnimalKind do
WriteLn(AK);
end.Code language: Delphi (delphi)

- 集合型別
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
type
// 定義列舉型別
TAnimalKind = (Duck, Cat, Dog);
// 以列舉為基底定義集合型別
TAnimals = set of TAnimalKind;
var
Animals: TAnimals;
AK: TAnimalKind;
begin
// 集合指派,存入 Duck、Cat 兩個列舉值
Animals := [Duck, Cat];
// for-in 走訪集合內所有存在成員
for AK in Animals do
begin
WriteLn('找到動物:', AK);
end;
end.Code language: Delphi (delphi)

- 泛型清單(後續章節教學)
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
uses
SysUtils, Generics.Collections; // 引入泛型容器單元
type
TMyClass = class // 自訂類別,儲存數字與其平方
I, Square: Integer;
end;
// 實體化泛型物件清單,自動管理物件生命週期
TMyClassList = {$ifdef FPC}specialize{$endif} TObjectList<TMyClass>;
var
List: TMyClassList;
C: TMyClass;
I: Integer;
begin
List := TMyClassList.Create(true); // true:清單銷毀時自動釋放內部物件
try
// 迴圈建立物件並加入清單
for I := 0 to 9 do
begin
C := TMyClass.Create;
C.I := I;
C.Square := I * I;
List.Add(C);
end;
// for-in 直接走訪清單中每一個自訂物件
for C in List do
WriteLn(C.I, ' 的平方為 ', C.Square);
finally
FreeAndNil(List); // 安全釋放清單,避免記憶體洩漏
end;
end.
Code language: Delphi (delphi)
備註:此範例用到類別與泛型,初學者可先跳過,後續物件導向章節會完整講解。