Delphi 11 编程语言的完整介绍 作者:Marco Cantu 译者:豆豆爸
在我们开始实际编写 Object Pascal 语言的语句之前,有必要强调一下 Object Pascal 编码风格的要素。 我在这里要讨论的问题是这样的: 除了语法规则(我们还没有浏览过),你应该如何编写代码? 这个问题没有唯一的答案,因为个人喜好会决定不同的风格。 不过,在注释、大写字母、空格以及多年前所谓的 “漂亮打印”(pretty-printing,对我们人类来说漂亮,而不是针对计算机,现在这个词已经过时了)方面,你需要知道一些原则。
一般来说,任何编码风格都是以清晰性目标。你所决定的风格和格式是一种简写形式,表明了具体代码的目的。保持清晰的一个关键工具就是一致性—即无论你选择什么风格,都要确保在整个项目和跨项目中遵循它。
小贴士: 集成开发环境(IDE)支持自动格式化代码(在单元或项目级别): 你可以使用 Ctrl+D 键要求编辑器重新格式化你的代码。在同一套规则之下,你可以通过调整约 40 种不同的格式化元素(在 IDE 选项中可以找到)来改变这些规则,甚至可以与团队中的其他开发人员共享这些设置,使格式保持一致。不过,自动格式化不支持某些最新的语言功能。
虽然代码通常是不言自明的,但在程序源代码中添加大量注释还是很有必要的,这样可以进一步向他人(以及在未来很长时间内查看代码时向自己)解释为什么要以这样方式编写代码,以及可能的假设是什么。
在传统的 Pascal 语言中,注释只能用大括号或括号星号组合括起来。现代版本的语言也接受 C/C++ 风格的单行注释、双斜线,这种注释延申到行尾,不需要符号来表示结束:
// This is a comment up to the end of the line
{ This is a
multi-line comment }
(* This is another
multi-line comment *)
第一种形式的单行注释是迄今为止最常见的注释,但它最初并不是 Pascal 的一部分,而是从 C/C++ 以及 C#、Objective-C、Java 和 JavaScript 中借用的。C/C++ 还使用 /* comment */ 语法来表示多行注释。
第二种形式比第三种形式更常用,而第三种形式在欧洲通常更受欢迎,因为许多欧洲键盘都缺少小括号符号(或尽管有多个按键组合,但还是难以使用)。换句话说,最古老的语法有点过时了。
至行尾的单行注释对于简短注释和注释出一行代码非常有用。到目前为止,它们是现代 Object Pascal 语言中最常见的注释形式。
提示: 在集成开发环境编辑器中,可以通过直接按键来注释或取消注释当前行(或一组选定的行)。Ctrl+/ 组合键用于美式键盘布局,但在其他键盘布局上则有所不同(取决于物理 键的位置)。实际的组合键可在编辑器的弹出菜单中查看。
三种不同形式的注释有助于标记嵌套注释。如果你想注释掉几行源代码以禁用它们,而这几行又包含一些真正的注释,你就不能使用相同的注释标识符:
{
code...
{Nested comment, creating problems}
code...
}
上面的代码会导致编译器错误,因为第一个封闭括号表示整个注释部分的结束。如果使用第二个注释标识符,就可以写出以下正确的代码:
{
code...
// This comment is OK
code...
}
另一种方法是如上所述注释掉一组行,因为这将在注释行上添加第二个 // 注释,你可以通过取消注释同一个块(保留原来的注释)来轻松移除。
注解:如果在花括号或小括号星号后跟上美元符号(KaTeX parse error: Expected '}', got 'EOF' at end of input: …如我们在第一个演示中看到的 {APPTYPE CONSOLE} 。 编译器指令指示编译器做一些特殊的事情,本章末尾将对编译器指令进行简要说明。
实际上,编译器指令仍然是注释。例如,{$X+ 这是注释} 是合法的。它既是一个有效的编译器指令,也是一个注释,不过大多数理性的程序员可能会倾向于将指令和注释分开。
有一种特殊的注释,在其他编程语言中也很常见,编译器会以特殊方式处理它。这些特殊注释由编译器生成XML文件格式的附加文档,可供IDE的Help Insight直接使用。
注解:在 Delphi IDE 中,Help Insight 会自动显示符号的相关信息(包括其类型和定义位置)。通过 XML Doc 注释,您可以用写入源代码本身的具体细节来增强这些信息。
XML 文档通过使用///
注释或{!
注释启用,您可以在这些注释内使用一般文本或(更好的是)特定的XML标签来表示被注释的符号、其参数和返回值以及更多信息等。这是一个非常简单的自由形式文本示例:
public
/// This is a custom method, of course
procedure CustomMethod;
如果启用了XML 文档生成,编译器会将信息添加到生成的XML输出中,如下所示:
This is a custom method, of course
在IDE中,当您悬停在符号上时,将显示相同的信息,如图1.4所示。
图 1.4: Delphi IDE 的 Help Insight显示以 /// 注释的 XML 文档信息
如果您按照建议的指南在注释中提供概要部分,这同样会显示在 Help Insight 窗口中:
public
/// This is a custom method, of course
procedure CustomMethod;
这样做的好处是你可以使用许多其他 XML 标记来表示参数、返回值和更详细的信息、 返回值和更多详细信息。可用的标记列于:
http://docwiki.embarcadero.com/RADStudio/en/XML_Documentation_Comments
程序由许多不同的符号组成,您可以使用这些符号来命名各种元素(数据类型、变量、函数、对象、类等)。虽然您几乎可以使用任何标识符,但还是有一些规则必须遵守:
以下是 IdentifiersTest 应用程序中列出的经典标识符示例:
MyValue
Value1
My_Value
_Value
Val123
_123
这些是合法的 Unicode 标识符示例(其中最后一个有点极端):
Cantù (Latin accented letter)
结 (Cash Balance in Simplified Chinese)
画像 (picture in Japanese)
☼ (Sun Unicode symbol)
以下是几个无效标识符的例子:
123
1Value
My Value
My-Value
My%Value
小贴士: 如果您想在运行时检查标识符是否有效(这很少需要,除非您正在编写一个工具来帮助其他开发人员),您可以使用运行时库中的一个名为
IsValidIdent
的函数。
与许多其他语言(包括所有基于C语法的语言,如C++、Java、C#和JavaScript)不同,Object Pascal编译器忽略标识符的大小写或大写形式。因此,标识符Myname
、MyName
、myname
、myName
和MYNAME
都是完全相同的。我个人认为,大小写不敏感绝对是一个积极的特性,因为在大小写敏感的语言中,错误的大写可能会导致语法错误和其他细微的错误。
然而,如果考虑到您可以在标识符中使用Unicode,情况就会变得有点复杂,因为大写版本的字母被视为相同的元素,而相同字母的重音版本被视为不同的符号。换句话说:
pascalCopy codecantu: Integer;
Cantu: Integer; // 错误:重复标识符
cantù: Integer; // 正确:不同的标识符
注解:对于语言的大小写不敏感性规则,有一个特殊的例外:由于 C++ 的兼容性问题,组件包的 Register 过程必须以大写字母 R 开头。当然,在引用其他语言导出的标识符(例如本地操作系统函数)时,可能必须使用正确的大写形式。
不过,这也有一些微妙的不足。。首先,你必须意识到这些标识符实际上是相同的,因此你必须避免将它们作为不同的元素使用。其次,你应该尽量一致地使用大写字母,以提高代码的可读性。
虽然编译器不会强制使用大小写,但这是一个良好的习惯:当一个标识符由几个连续的单词组成时(不能在标识符中插入空格),单词的每个首字母都应大写:
MyLongIdentifier
MyVeryLongAndAlmostStupidIdentifier
这通常被称为“Pascal命名法”,与基于C语法的Java和其他语言的所谓“驼峰命名法”形成对比,后者将内部单词的首字母大写,如:
myLongIdentifier
事实上,在 Object Pascal 代码中,局部变量使用驼峰式命名(首字母小写),而类、参数和其他全局元素则使用 Pascal 命名,这种情况越来越常见。无论如何,在本书的源代码片段中,我尝试对所有符号统一使用 Pascal 命名格式。
编译器完全忽略的其他元素是您添加到源代码中的空格、换行和制表符。所有这些元素统称为空白字符。
空白字符仅用于提高代码的可读性,对编译没有任何影响。与传统的 BASIC语言不同,Object Pascal 允许在跨行编写语句,将一条长指令分成两行或多行。允许跨行编写语句的缺点是,你必须记住添加分号来表示语句的结束,或者更准确地说,分隔一条语句和下一条语句。将编程语句分隔在不同行的唯一限制是,一个字符串字面量不能跨越几行。
以下几行代码虽然奇怪,但都表示同一条编译语句:
A := B + 10;
A :=
B
+
10;
A
:=
// This is a mid-statement comment
B + 10;
对于空格和多行语句的使用没有固定的规则,只是一些经验之谈:
1.2.6 缩进
最后关于使用空格的一些建议涉及典型的 Pascal 语言格式和缩进。
注解:缩进规则是因个人喜好而异的,我不想卷入“制表符与空格”的争论。在这里,我只是指出这是Object Pascal世界中“最常见”或“标准”的格式样式,这也是Delphi库源代码中使用的样式。在Pascal世界的历史上,这套规则曾被称为pretty-printing(漂亮打印),一个现在相当不常见的术语。
这条规则很简单: 每次需要编写复合语句时,都要在当前语句的右侧缩进两个空格(而不是像 C 语言程序员通常会使用的制表符)。另一个复合语句内的复合语句缩进 四个空格,以此类推:
if ... then
statement;
if ... then
begin
statement1;
statement2;
end;
if ... then
begin
if ... then
statement1;
statement2;
end;
同样,程序员对这个规则也有不同的理解。有些程序员将 begin
和 end
语句缩进到内部代码的层次,有些程序员则将 begin 放在前一条语句的末尾(类似于 C 语言)。这主要是个人喜好的问题。
类似的缩进格式通常用于变量列表或数据类型,在 type
和 var
关键字之后的变量或数据类型列表中使用类似的缩进格式:
type
Letters = ('A', 'B', 'C');
AnotherType = ...
var
Name: string;
I: Integer;
注意:在上面的代码中,您可能想知道为什么两个不同的类型,
string
和Integer
用不同的大小写来表示初始字母。正如最初的Object Pascal Styles Guide所述,“像Integer
这样的类型只是标识符,并带有首字母大写;而string
等则用保留字string
声明,保留字应全部小写。”
在过去,当声明自定义类型和变量时,通常还使用基于列缩进分隔符。在这种情况下,上面的代码将如下所示:
type
Letters = ('A', 'B', 'C');
AnotherType = ...
var
Name : string;
I : Integer;
缩进也常用于延续上一行的语句或函数的参数(如果不将每个参数单独放在一行的话):
MessageDlg('This is a message',
mtInformation, [mbOK], 0);
为了便于阅读和编写 Object Pascal 代码,集成开发环境编辑器具有一种称为语法高亮的功能。根据输入的单词在语言中的含义,它们会以不同的颜色和字体样式显示。默认情况下,关键字使用粗体,字符串和注释使用彩色(通常使用斜体),以此类推。
保留字、注释和字符串可能是受益于这一功能最多的三个元素。你可以一目了然地看到拼写错误的关键词、未正确结束的字符串以及多行注释的长度。
您可以使用集成开发环境选项对话框的编辑器颜色页面轻松自定义语法高亮设置。如果只有你一个人使用电脑查看 Object Pascal 源代码,请选择你喜欢的颜色。如果你与其他程序员密切合作,你们应该就标准颜色方案达成一致。我经常发现,在一台语法颜色与我通常使用的计算机不同的计算机上工作,真的很令人困惑。
错误洞察和代码洞察
集成开发环境编辑器还有很多功能可以帮助你编写正确的代码。最明显的是 Error Insight,它会在不理解的源代码元素下画上红色方格,就像文字处理器标记拼写错误一样。
注解:有时,你需要编译一次程序,以避免 Error Insight 对完全合法的代码做出错误提示。另外,保存窗体等文件可能会强制引入当前组件所需的单元,从而解决不正确的 Error Insight 指示。Delphi 10.4 中首次引入的基于 LSP(基于语言服务器协议),这些问题已在新的 Code Insight 中得到了很大程度的解决。
其他功能,如 “代码补全”(Code Completion),可在您编写代码的地方提供合法符号列表,从而帮助您编写代码。当函数或方法有参数时,你可以在输入时看到参数列表。你还可以将鼠标悬停在某个符号上,查看其定义。不过,这些都是编辑器的特定功能,我不想详细讨论,因为我想继续专注于语言,而不是详细讨论 IDE 编辑器(尽管它是迄今为止编写 Object Pascal 代码最常用的工具)。