几篇长文过后,打算来几个短篇了。短篇打算用随笔的形式发布,内容相对比较简单,只涉及一两个语法点。
for循环是几乎所有过程式编程语言都会有的语句,但在不同类型的语言中,它的语义又有差别。就是说明在Delphi语言中,for循环的语法是:
for counter := initialValue to/downto finalValue do statment
首先,for循环必须有一个并且只能有一个计数器(Counter)变量,计数器变量有以下几个特点:
- 该计数器变量必须是序数类型(Ordinal Type),也就是:整数、枚举、字符、布尔类型这几大类。因而,初值与终值也只能与计数器类型相同,为序数类型。
- 编译器建议计数器使用局部变量,否则会给出警告;不能使用对象成员变量或类成员变量,否则编译器会提示出错。这么做的目的,也与下一条有不小的关系。
- 循环体中无法直接更改计数器变量的值。
for循环的计数器如此设计,与该语句的另外一个特点也有很大的关系:
在循环开始前,会首先确定initialValue与finalValue的值,也就是说,finalValue是一个值,而不是一个表达式。这就意味着:只要不在循环体中改变counter的值,并且循环体中不会break的话,循环的次数就是确定的。因而,Delphi(或者说是Pascal)里的for语句是一个典型的、确定次数的循环。在C类语言中,条件项是一个表达式,每次循环都会计算表达式的值——这意味着,如果表达式中包含一个函数,并且编译器没有进行非常激进的优化,那么每次都会调用该函数。在C类语言中,这种激进的优化是很危险的,因为就算编译器能够判断循环体中的代码会不会改变该函数的运行结果(实事上也很难判断),在多线程流行的今天,编译器也无法判断会不会有其它线程会改变函数结果。而在Pascal中,确定的for循环在语法上就规定了:如果想要每次通过一个函数确定终止条件,那就请用while/repeat吧,for做不到。
正因如此,用一个全局变量是危险的,因为虽然不能在循环体中直接改变counter的值,但却可以通过调用其它函数改变全局变量的值。同样,对于局部变量的counter,我们也还是有办法改变它的值的,方法类似,也是比较麻烦的。间接改变counter的值也是有效果的,但是强烈不建议做这种事,会使代码的可读性变差。如果有需要的话,还是老老实实的用while/repeat吧。
最后,delphi中的for没有类似basic中的step,也就是每次循环counter都顺序的增加或减少1。想要类似basic中步长的话,那就请用counter自己乘吧。
补充一点儿扩展知识:如果计算器变量是全局变量的话,特点1(序数类型)是有办法突破的(比如使用PAnsiChar类型)。也不知道算是Delphi的特性还是bug,反正在Free Pascal中是不行的。因此,我还是建议老老实实的按语法走,搞这种歪路子不利于优良代码风格的形成。