Object Pascal 学习笔记,Delphi 11 编程语言的完整介绍 作者: Marco Cantu 笔记:豆爸
3.4 For循环语句
Object Pascal
语言具有大多数编程语言中典型的循环语句,包括for
、while
、repeat
语句,以及更现代的for-in
(或for-each
)循环。如果您使用过其他编程语言,大多数这些循环都会很熟悉,因此我将简要介绍它们(指出与其他语言的关键区别)。
Object Pascal
中的for
循环严格基于一个计数器,该计数器在每次循环执行时可以增加或减少。以下是用于累加前十个数字的for
循环的简单示例(ForTest演示的一部分):
varTotal, I: Integer;
beginTotal := 0;for I := 1 to 10 doTotal := Total + I;Show(Total.ToString);
对于那些好奇的人,输出是 55。在引入内联变量后编写 for 循环的另一种方法是在声明中声明循环计数器变量(其语法在某种程度上类似于 C 和后面讨论的派生语言中的 for 循环):
varTotal: Integer;
beginTotal := 0;for var I := 1 to 10 doTotal := Total + I;Show(Total.ToString);
在这种情况下,您还可以利用类型推断省略类型说明。上述完整的代码片段变为:
varTotal: Integer;
beginTotal := 0;for var I := 1 to 10 doTotal := Total + I;Show(Total.ToString);
使用内联循环计数的一个优势是该变量的作用域将仅限于循环:在for
语句之后使用它将导致错误,而通常在循环之外使用循环计数时只会得到一个警告。
Pascal中的for
循环比其他语言更不灵活(不允许指定不同于1的增量),但它简单易懂。作为对比,这是用C语言语法编写的相同for
循环:
int total = 0;
for (int i = 1; i < = 10; i++) {total = total + i;
}
在这些语言中,增量是一个可以指定任何种类序列的表达式,这可能导致许多人认为是令人难以阅读的代码,如下所示:
int total = 0;
for (int i = 10; i > 0; total += i--) {// ...
}
然而,在Object Pascal中,您只能使用单步增量。如果要测试更复杂的条件,或者要提供自定义计数器,您将需要使用while
或repeat
语句,而不是for
循环。
单步递增的唯一替代方法是单步递减,或使用 downto 关键字的反向 for 循环:
varTotal, I: Integer;
beginTotal := 0;for I := 10 downto 1 doTotal := Total + I;
注解:反向计数非常有用,例如,当你在影响一个基于列表的数据结构时,你就会进行循环。在删除某些元素时,你通常会向后移动,因为正向循环可能会影响你正在操作的序列(也就是说,如果你删除了列表中的第三个元素,第四个元素就会变成第三个:现在你正在操作第三个元素,移动到下一个(第四个),但实际上你正在操作的是第五个元素,跳过了一个)。
在Object Pascal中,for
循环的计数器不需要是一个数字。它可以是任何序数类型的值,例如字符或枚举类型。这有助于编写更易读的代码。以下是基于Char
类型的for
循环的示例:
varAChar: Char;
beginfor AChar := 'a' to 'z' doShow(AChar);
这段代码(ForTest 程序的一部分)显示了所有英文字母,每个字母都在输出 Memo 控件的单独一行中。
注解:在第 2 章的 CharsTest 示例中,我已经展示过一个类似的演示,但它是基于整数计数器的。不过,在那个示例中,字符是串联在一个输出字符串中的。
下面是另一个代码片段,展示了基于自定义枚举的 for 循环:
typeTSuit = (Club, Diamond, Heart, Spade);
varASuit: TSuit;
beginfor ASuit := Club to Spade do// ...
最后一个循环在数据类型的所有元素上循环。更好的写法是明确地对数据类型的每个元素进行操作(使其更灵活地适应定义中的变化),而不是特别指明第一个和最后一个元素:
for ASuit := Low(TSuit) to High(TSuit) do
类似地,为数据结构的所有元素编写for
循环是相当常见的,例如字符串。在这种情况下,您可以使用来自ForTest
项目的此代码:
varS: string;I: Integer;
beginS := 'Hello world';for I := Low(S) to High(S) doShow(S[I]);
如果不想指明数据结构的第一个和最后一个元素,可以使用 for-in 循环来代替,这是一种特殊用途的 for 循环,将在下一节讨论。
注解:在 Object Pascal 中,编译器如何处理使用 [] 操作符直接读取的字符串数据,以及如何确定字符串的下界和上界,仍然是一个相当复杂的问题,即使现在所有平台的默认值都是一样的。这将在第 6 章中介绍。
对于使用基于零的索引的数据结构,你需要从索引零到数据结构的大小或长度之前的索引进行循环。编写此代码的常见方法如下:
for I := 0 to Count - 1 do ...
for I := 0 to Pred(Count) do ...
关于 for 循环的最后一个注意事项是,循环结束后循环计数器会发生什么变化。简而言之,该值是未指定的,如果在循环结束后试图使用 for 循环计数器,编译器会发出警告。为循环计数器使用内联变量的一个好处是,该变量仅在循环本身中定义,在循环结束语句后将无法访问,从而导致编译器出错(这提供了更强的保护):
beginvar Total := 0;for var I: Integer := 1 to 10 doInc(Total, I);Show(Total.ToString);Show(I.ToString); // 编译器错误:未声明的标识符'I'
end;