Object Pascal 语言(以及 C 语言的类似功能)强调的另一个重要思想是例程的概念,例程基本上是一系列具有唯一名称的语句,可以多次调用。例程(或函数)通过名称来调用,这样就可以避免重复编写相同的代码,并允许在整个程序的多个地方使用某些代码的单一版本。从这个角度看,你可以将例程视为一种基本的代码封装机制。
在Object Pascal中,例程可以有两种形式:过程和函数。理论上,过程是您要求计算机执行的操作,而函数是返回值的计算。这种区别强调了函数有一个结果、返回值或类型,而过程则没有。C语言语法只提供了函数这一种机制。而在C语言中,过程就是一个结果为 void(或 null)的函数。
这两种例程都可以有多个指定数据类型的参数。正如我们稍后将看到的,过程和函数也是类方法的基础,在这种情况下,两种形式之间的区别依然存在。事实上,与 C、C++、Java、C# 或 JavaScript 不同,在声明例程或方法时,您需要使用这两个关键字(procedure和function)之一。
实际上,即使有两个独立的关键字,函数和过程之间的区别也非常有限:你可以调用函数来执行某些任务,然后忽略结果(可能是一个可选的错误代码或类似的东西),或者调用存储过程,在其中一个参数中传回一个结果(本章稍后将详细介绍引用参数)。
以下是使用Object Pascal语言语法定义过程的示例,使用了procedure
关键字,该示例属于FunctionTest
项目:
procedure Hello;
begin
Show('Hello world!');
end;
作为比较,这是使用C语言语法编写的相同函数,它没有关键字,即使没有参数也需要括号,并且有一个void关键字表示没有返回结果:
void Hello()
{
Show("Hello world!");
};
实际上在C语言语法中,过程和函数之间没有区别。然而,在Pascal语言语法中,对函数进行了区分,因为函数有一个特定的关键字(function),并且必须有一个返回值(或返回类型)。
注解: Object Pascal与其他语言之间还有一个非常特殊的语法差异,那就是在定义中函数或过程签名的末尾,begin 关键字之前有一个分号。
有两种方法来表示函数调用的结果,一种是将值赋值给函数的名称,另一种是使用Result
关键字:
/ 经典的Pascal风格
function DoubleOld(Value: Integer): Integer;
begin
DoubleOld := Value * 2;
end;
// 现代的替代方式
function DoubleIt(Value: Integer): Integer;
begin
Result := Value * 2;
end;
注解: 与经典的Pascal语法不同,现代Object Pascal实际上有三种表示函数结果的方法,包括在本章“带有结果的Exit”部分中讨论的Exit机制。
使用Result
而不是函数名称来表示函数的返回值是最常见的语法,使代码更易读。使用函数名称是一种经典的Pascal标志,现在很少使用,但仍然受到支持。
同样,通过比较,同样的函数使用C语言语法可以这样写:
int DoubleIt(int Value)
{
return Value * 2;
};
注解: 在基于C语法的语言中,return语句表示函数的结果,但也终止执行,将控制权返回给调用者。另一方面,在Object Pascal中,向函数的结果赋值不会终止函数执行。这就是为什么结果通常被用作常规变量的原因,例如为其分配初始默认值,甚至在算法中修改其结果。同时,如果需要停止执行,还需要使用
Exit
或其他流控制语句。所有这些在以下“带有结果的Exit”部分中都有更详细的介绍。
如果这些例程是这样定义的,那么调用语法就相对简单,只需输入标识符,然后在括号内输入参数即可。在没有参数的情况下,可以省略空括号(与基于C语法的语言不同)。以下代码片段以及接下来的几个代码片段都是本章FunctionsTest
项目的一部分:
// 调用过程
Hello;
// 调用函数
X := DoubleIt(100);
Y := DoubleIt(X);
Show(Y.ToString);
这里演示了代码封装的概念。当您调用DoubleIt
函数时,您无需知道用于实现它的算法。如果以后找到了更好的方法来使数字加倍,您可以轻松更改函数的代码,但调用代码将保持不变(尽管执行函数可能会变得更快)。
相同的原则也可以应用于Hello
过程:我们可以通过更改此过程的代码来修改程序的输出,而主程序代码将自动更改其效果。以下是如何更改过程实现代码的方式:
procedure Hello;
begin
Show('Hello world, again!');
end;