单元 程序头:uses(子句列出了那些链接到程序的单元),block(声明,命令语句)
一个程序包括:
• 一个程序头(program heading)
• 一个uses 子句(可选),和
• 一个包含声明和命令语句的块(block)
一个单元以单元头(unit heading)开始,后面跟interface、implementation、initialization
和finalization 部分,后面两个部分是可选的
一个uses 子句可以出现在:
• 程序或库的工程文件
• 单元的接口部分,和
• 单元的实现部分
在单元声明以及uses 子句中(尤其是在Linux 下),单元名称必须和文件名大小写一致。在其它情
况(比如使用限定符的标志符),单元名是大小写无关的。要避免在单元引用中出现问题,要明确指出单元文件:
uses MyUnit in "myunit.pas";
如果像上面这样在工程文件中明确引用一个单元,在其它源文件中就可以像下面那样简单地引用它,
而不必考虑大小写问题:
uses Myunit;
uses 子句给编译器提供各模块间的依赖信息,因为这些信息是存于模块自身的,所以,Object Pascal
程序不需要makefile 文件、头文件以及include 预处理指令(这些概念你可能要参考C 语言)。每当一个
工程调入IDE 时,Project Manager 创建一个makefile,但只有在包含多个工程的工程组中才保存这些文
件。
• 单元源文件 ( .pas)
• 工程文件 ( .dpr)
• 包源文件 ( .dpk)
• 窗体文件,扩展名为 .dfm(Delphi)或 .xfm(Kylix)
• 资源文件,扩展名为 .res (已经编译的资源文件)
• 工程选项文件,扩展名为 .dof(Delphi)或 .kof(Kylix)
要改变程序的图标,可使用Project Options 对话框。
<Leo> 在窗体设计器上右击弹出PopMenu有View as Text项,可察看事件和过程的关联
事件句柄通过窗体文件(Windows 下是 .dfm,Linux 下是 .xfm)赋给指定的事件
空格(#32)和控制符(#0 到#31,其中#13 叫回车符或行的结束符)被称为空白符(blank)。
特殊符号是非文字和数字字符,或这类字符的组合,它们有固定的意义。
‘[’相当于‘(.’,‘]’相当于‘.)’;‘(*’和‘*)’分别相当于‘{’和‘}’(表示注释)。
,!(惊叹号)、 ”(双引号)、 %(百分号)、 ?(问号)、 /(反斜杠)、 _(下划线)、 |(通道)和 ~(破折
号)不是特殊符号
$前缀表示一个16 进制数字,比如$8F
标签是一个不超过4 位的阿拉伯数字序列,也就是从0 到9999,打头的0 没有意义
。若单引号中没有内容(’’),它被称为空串(null string)。在一个引用串中,两个连续的单引号(’’)表示一个字 符,也就是单引号本身(’)控制串由一个或多个控制字符(控制符)所组成,每个控制符包含一个#,后跟一个无符号整数(10
进制或16 进制),整数的范围从0 到255,表示相应的ASCII 字符。下面的控制串
#89#111#117
就相当于引用串
’You’
运算符包括:@ not ^ * / div mod and shl shr as + - or xor = > < <> <= >= in 和 is。
一些运算符的行为因为传给它们的数据类型不同而不同。比如,not 运算符用于整数时,是对它的
位进行求反运算,而对布尔类型进行逻辑非运算。
除了 ^ ,is 和 in,其它运算可应用在Variant 类型上。
• 不管x 和y 的类型是什么,x/y 的结果总是扩展类型(extended);对其它运算符,只要有一个
运算数是实数类型,它的结果就是扩展类型;另外,只要有一个运算数是Int64 类型,它的结果就是Int64 类型;否则
,结果就是整数类型。如果一个运算数是整数的子界类型,它就像整数类型一样被对待。
• x div y 的值取整数,也就是取得x/y 的值,然后以0 的方向取得最近的整数。
• mod 运算返回对运算数进行整数除后得到的余数。换句话说,就是x mod y = x - (x div y)*y。
布尔运算符not、and、or 和xor 作用于任何布尔类型的运算数,并返回一个布尔类型的值。
使用 $B 编译器指示字控制计算方式,默认状态是 {$B-},它采用部分计算。要在局部进行完全计
算,在代码中使用 {$B+} 指示字。你也可以在Compiler Options 对话框中选择Complete Boolean
Evaluation 选项,此时在整个项目范围使用完全计算。
<Leo>///部分计算 equals 短路计算 in C++/C#
若任何一个运算数是variant 类型,编译器总是进行完全计算(即使在 {$B-} 状态下)
Logical (bitwise) operators(位逻辑运算符):not and or xor shl shr
• 位反(not)运算的返回类型和运算数相同;
• 若and、or 或xor 的运算数都是整数类型,则它的返回类型是包含运算数所有可能的值、且范围最小的预定义(内置)整数类型;• 运算 x shl y 和 x shr y 把 x 的值向左或向右移 y 个位,也就等同于 x 乘或除以 2^y(2的 y 次方),返回类型 和 x 相同。比如,若 N 存储的是01101(10 进制的13),那么 N shl 1 返11010(10 进制26)。注意,y 的值被解释为对 x 所属类型大小(位数)进行模运算,比如,若 x 是一个integer,x shl 40 被解释为 x shl 8,因为integer的大小是32 位(4字节),40 mod 32 等于8。
关系运算符 =、<>、<、>、<= 和 >= 都能对字符串进行操作 + 运算符连接两个字符串
• + 运算符的运算数可以是字符串、packed string(packed arrays of type Char)或字符。但是,若其中一个运算数
是宽字符(WideChar)类型,其它运算数必须是长字符串。
• + 运算符的返回结果和任何字符串类型是兼容的。但是,若运算数都是短字符串或字符,并且它们的组合长度大于255
,则返回结果取前面的255 个字符。
关系运算符 <、>、<= 和 >= 能对PChar 类型进行操作。其它的指运算符:+- 指针加减 ^ 取得指针所指的内容 = <>
等于 不等于
对于Pointer 类型,在dereference 之前必须进行类型转换。
• 若I 是一个整数,P 是一个字符指针,那么P + I 是把P 的地址加上I,也就是一个指向P 后面
第I 个字符处的指针(表达式I + P 等同于P + I);P – I 是把P 的地址减去I,也就是一个指向P
前面第I 个字符处的指针。
• 若P 和Q 都是字符指针,那么P – Q 计算P 的地址(高地址)和Q 地址(低地址)之差,也就
是返回一个表示P 和Q 之间字符数目的整数。P + Q 没有意义。
Set operators(集合运算符):
+并集 - 差集 * 交集 <= 小于等于(子集)>= 大于等于(超集) =等于 <>不等于 in 成员关系
以下规则适用于 +、– 和 * 运算符:
• 当且仅当序数(集合基础类型中的一个值)O 属于集合X 或集合Y(或同时属于X 和Y)时,
O 属于X + Y;当且仅当O 属于X 但不属于Y 时,O 属于X – Y;当且仅当O 同时属于X 和Y
时,O 属于X * Y。
• +、– 和 * 的运算结果属于集合类型set of A..B,这里A 是结果中的最小序数,B 是结果中的
最大序数。
以下规则适用于 <=、>=、=、<> 和 in 运算符:
• 只有当X(集合)中的每个成员也是Y(集合)中的成员时,X <= Y 才为真;Z >= W 等同于
W <= Z;只有当U(集合)和V(集合)正好拥有相同的成员时,U = V 才为真,否则U <> V
为真;
• 对于序数O 和集合S,只有当O 是S 的一个成员时,O in S 才为真。
• 除了实数和整数能一起比较外,两个运算数必须是兼容的类型;
• 对字符串进行比较,是依据它的每个字符在扩展ASCII 字符集中的顺序,字符类型被当作长度
为1 的字符串;
• 两个packed string 要进行比较,它们必须具有相同数目的元素;一个具有n 个元素的packed string
与一个字符串比较时,它被看作长度为n 的字符串;
• 只有当两个PChar 指针都指向同一个字符数组的范围内时,<、>、<= 和 >= 运算符才能作用
于它们;
• 运算符 = 和 <> 能以类或类引用类型作为运算数。当用于类类型时,= 和 <> 的计算规则与
指针一样,只有当C 和D 指向同一个实例对象时,C = D 为真,否则C <> D 为真;当用于类
引用时,只有当C 和D 表示同一个类时,C = D 为真,否则C <> D 为真。
as 和 is 运算符使用类和对象(实例)作为运算数,as 也用于接口类型。
@ 运算符返回一个变量、函数、过程或方法的地址,也就是说,@ 运算符构建一个指向运算数的
指针。
• 若X 是一个变量,@X 返回X 的地址(当X 是一个过程类型的变量时有特殊的规则,请参考语
句和表达式中的过程类型)。若默认的编译器指示字 {$T–} 在起作用,则@X 的类型是
Pointer(通用指针);在 {$T+} 状态下时,@X 的类型是 ^T,这里T 是X 的类型;
• 若F 是一个例程(一个函数或过程),@F 返回F 的入口点,@F 的类型总是Pointer;
• 当 @ 作用于类的方法时,必须使用类名来限定方法名。比如
@TMyClass.DoSomething
它指向TMyClass 的DoSomething 方法。
Set constructors(集合构造器)
[5, 6, 7, 8]
[ 5..8 ]
[red, green, MyColor]
[1, 5, 10..K mod 12, 23]
[’A’..’Z’, ’a’..’z’, Chr(Digit + 48)]
集合构造器[]表示空集
字符串、数组、数组属性以及指向字符串或数组的指针能被索引。比如:FileName[21]
强制类型转换的语法是
typeIdentifier(expression)
若表达式是一个变量,结果被称为variable typecast(变量转换);否则,结果是一个value typecast(值转换)。虽
然它们的语法相同,但它们有不同的转换规则。
在值转换中,类型标志符和转换的表达式必须都是有序类型或指针类型。值转换的例子包括
Integer(’A’)
Char(48)
Boolean(0)
Color(2)
Longint(@Buffer)
声明的语法以及声明的位置取决于要定义的标志符的种类。通常,声明只能出现在块(block)的开始处,
以及单元的接口或实现部分的开始处(在uses 子句之后)。
Hint 指示字platform、deprecated 和library 能附加在任何声明之后。在声明过程或函数的情况下,应
使用分号把hint 指示字和声明的其它部分分开。比如:
procedure SomeOldRoutine; stdcall; deprecated;
var VersionNumber: Real library;
type AppError = class(Exception)
...
end platform;
当源代码在{$HINTS ON} {$WARNINGS ON}状态下编译时,对使用上述指示字声明的标志符的每个引
用都将产生一个适当的提示或警告。使用platform 标记一个条目和特定的操作系统(比如Windows 和
Linux)相关;使用deprecated 表示条目已经废弃或支持它仅为了向后兼容性;使用library 表示依赖于
特定的库或组件框架(比如VCL 或CLX)。
赋值语句的格式如下
variable := expression
这里,variable 是任何变量引用,包括变量、变量类型转换、解除引用的指针,或者一个结构变量的组
成部分;expression 是任何一个赋值兼容的表达式。(在函数块中,variable 能被函数名取代,参考Procedures
and functions。
当启用扩展语法时({$X+}),调用函数也可以像调用过程那样 当这样调用函数时,它的返回值被忽略。
goto label
label: statement
label label;
label label1, ..., labeln;
• 复合语句或with 语句只是简单地执行一系列语句;
• 条件语句,也就是if 或case 语句,根据指定的标准,最多执行一个分支;
• 循环语句,包括repeat、while 和for 循环,重复执行一系列语句;
• 一组特殊的语句,包括raise、try...except 和try...finally 结构,用来创建和处理异常。
with 语句的语法是
with obj do statement
或
with obj1, ..., objn do statement
if 语句有两种形式:if...then 和if...then...else
比如,
if J = 0 then
Exit
else
Result := I/J;
if J <> 0 then
begin
Result := I/J;
Count := Count + 1;
end
else if Count = Last then
Done := True
else
Exit;
Case Statements(Case 语句):
case selectorExpression of
caseList1: statement1;
...
caseListn: statementn;
else
statements;
end
case I of
1..5: Caption := ’Low’;
6..9: Caption := ’High’;
0, 10..99: Caption := ’Out of range’;
else
Caption := ’’;
end;
selectorExpression 是任何一个有序类型的表达式(字符串无效),和C++一样的。
。Object Pascal 有三种循环:repeat 语句、while 语句和for 语句。
使用Break 和Continue 过程来控制repeat、while 或for 语句的流程。
repeat 语句的语法是
repeat statement1; ...; statementn; until expression
比如:
repeat
Write(’Enter a value (0..9): ’);
Readln(I);
until (I >= 0) and (I <= 9);
while 语句的语法是
while expression do statement
比如:
while I > 0 do
begin
if Odd(I) then Z := Z * X;
I := I div 2;
X := Sqr(X);
end;
for 语句的语法是
for counter := initialvalue to finalvalue do statement
或
for counter := initialvalue downto finalvalue do statement
比如:for C := Red to Blue do Check(C);
一个块包含一系列的声明,后面跟一个符合语句。所有的声明必须一起出现在块的开始处,所以,块的
形式是
declarations;
begin
statements;
end;
比如:
function UpperCase(const S: string): string;
var
Ch: Char;
L: Integer;
Source, Dest: PChar;
begin
...
end;
类型可以分为基本(fundamental)和一般(generic)类型。基本类型的范围和形式是相同的,不管是基于何种CPU 和
操作系统;而一般类型的范围和形式是平台相关的
大多数内置类型属于基本类型,但少数整数、字符、字符串和指针类型属于一般类型。
在需要的时候使用一般数据类型是一个好注意,因为它们提供优化的性能和轻便性。
类型也可以分为简单类型、字符串类型、结构类型、指针类型、过程类型和变体类型。
下面的提纲显示了Object Pascal 数据类型的分类:
simple简单类型
ordinal有序类型
integer 一般(generic)整数类型是Integer 和Cardinal
基本整数类型包括Shortint、Smallint、Longint、
Int64、Byte、Word 和Longword
character 基本字符类型是AnsiChar 和WideChar。
一般字符类型是Char,它相当于AnsiChar。
Boolean 布尔类型为Boolean、ByteBool、WordBool和LongBool,Boolean是首选的
enumerated
subrange
real实数类型 Real48 Single Double Extended Comp Currency
string 字符串类型 ShortString AnsiString WideString
structured
set
array
record
file
class
class reference
interface
pointer
procedural
Variant
(type identifier)
标准函数SizeOf 作用于所有变量和类型标志符,它返回一个整数,表明存储指定类型的数据所需要的内存数(字节)。
有序类型包括整数、字符、布尔、枚举和子界类型。有序类型定义一个有次序的数值集合,除了它的第一个值以外,其它每个值都有一个唯一的前驱值(predecessor);除了最后一个外,其它每个值都有一个唯一的后继值(successor)
Ord 有序类型表达式 序数值
Pred 有序类型表达式 表达式的前驱值
Succ 有序类型表达式 表达式的后继值
High 有序类型的变量或标志符 类型的最大值
Low 有序类型的变量或标志符 类型的最小值
例程High、Low、Succ、Pred、Inc、Dec、IntToStr 和IntToHex 完全支持Int64 参数。
而且,Round、Trunc、StrToInt64 和StrToInt64Def 返回Int64 类型的值;
少数例程(包括Ord)根本不能对Int64 数值进行操作。
当把整数类型的最后一个值增大或把第一个值减少时,结果将回到整数类型的开头或尾部
。内置函数Chr,返回一个在AnsiChar 或WideChar取值范围内任意一个整数的字符值。比如,Chr(65)返回字母A。
<Leo>Inc()是什么呢?
对ByteBool、WordBool 和LongBool 来说,若它的序数不为0,它就被认为是True。在一个需要Boolean类型的环境种,
编译器自动把非0 值转换为True。
在Object Pascal 中,布尔表达式不能和整数或实数进行换算。所以,若X 是一个整数变量,语句
if X then ...;
会产生编译错误
定义一个枚举类型,使用下面的语法:
type typeName = (val1, ..., valn)
type Size = (Small = 5, Medium = 10, Large = Small + Medium);
比如:type Suit = (Club, Diamond, Heart, Spade);
在声明变量时,可以直接使用(val1,…,valn)结构,它就像一个类型名称:
var MyCard: (Club, Diamond, Heart, Spade);
子界类型表示其它有序类型(称为基础类型)的一个子集:它的形式为Low..High
• Extended 类型比其它实数类型有更高的精度,但不够轻巧。当使用Extended 类型创建的文件要跨平
台共享时,务必小心。
• Comp(computational)类型对Intel CPU 是优化的,表示为64 位整数,但它被分类位实数类型,因为它的行为不像有序类型(比如,你不能递增和递减)。保留此类型只是为了向后兼容性,使用Int64可获得更好的性能。
• Currency 类型有固定的小数点,可以把在货币运算中出现的错误减到最少。It is stored as a scaled
64-bit integer with the four least significant digits implicitly representing decimal places. 当在赋值
语句和表达式中与其它实数类型混合使用时,它的值会自动除以或乘上10000。
在赋值语句和表达式中,字符串类型可以混合使用,编译器自动进行所需的转换。但对于过程或函数,
当使用引用方式传递字符串时,类型必须正确。
在默认的{$H+}状态下,编译器把string(当它的后面没有包含数字的中括号时)解释为AnsiString;
使用{$H-}指示字把它解释为ShortString。
标准函数Length 返回一个字符串的字符个数;SetLength 设置一个字符串的长度。
可以像数组一样对字符串使用索引。若S 是一个字符串变量,i 是一个整数表达式,则S[i]表示S 中第
i 个字符(或者,严格说来,是第i 个字节)。对于ShortString 或AnsiString,S[i]是AnsiChar 类型;对于
WideString,S[i]是WideChar 类型。语句 MyString[2] := ’A’; 把值A 赋给MyString 的第2 个字符。
若S 是一个ShortString 变量,Ord(S[0]),和Length(S)一样,将返回S 的长度;给S[0]赋值,就像调用SetLength
,将改变S 的长度。
var MyString: string[100];声明一个叫做MyString 的变量,它的最大长度是100 字节,
标准函数High 和Low 能作用于short-string 类型名和变量,High 返回它的最大长度,Low 返回0。
AnsiString 类型又称为长字符串,它可以动态分配,并且长度只受内存限制。它使用8 位ANSI 字符。
长串变量是一个指针,占据4 个字节的内存。当变量为空时(也就是长度为0 的字符串),指针为nil,
此时,它不需要额外的内存
因为长串变量是指针,所以,两个或更多的变量可以引用同一个值,而不必使用额外的内存。编译器利
用这一点节省资源和进行快速赋值。只要一个长串变量被销毁或赋给一个新值,原来的串(变量的前一
个值)引用计数减1,而新的值(如果有的话)引用计数加1。若引用计数为0,它的内存被释放。这个
过程被称为reference-counting。当使用字符串索引改变其中的一个字符时,若字符串的引用计数大于1,
将生成串的一个拷贝,这被称为copy-on-write 机制。
WideString 类型是动态分配的、由16 位Unicode 字符所构成的字符串。在大多数方面,它和AnsiString
相似。(注:宽字符串没有引用计数,不支持copy-on-write 机制,但支持内存动态分配。)
在Win32 下,WideString 和COM BSTR 类型兼容。
Object Pascal 支持单字节和多字节字符以及字符串,适用的类型有:Char、PChar、AnsiChar、PAnsiChar
和AnsiString。对多字节字符串使用索引是不可取的,因为S[i]表示S 中第i 个字节(不一定是第i 个字
符),但是,标准字符串处理函数有多字节版本,它们还实现了locale-specific ordering for characters(多
字节函数的名称通常以Ansi 开头,比如StrPos 的多字节版本是AnsiStrPos)。多字节支持依赖于操作系
统和本地设置(current locale)。
Object Pascal 使用WideChar、PWideChar 和WideString 类型支持Unicode 字符和字符串。
字符串常量和类型PChar、PWideChar 是赋值兼容的,后两者表示指针,
它们指向一个以0 结尾的Char 或WideChar 字符数组。
一个字符指针(PChar 或PWideChar)可以像数组一样使用索引。
结构类型包括集合、数组、记录,也包括类、类引用(class-reference)和接口类型。
除了集合只能包含有序值以外,结构类型可以包含其它的结构类型,且结构的层次不受限制。
默认情况下,一个结构类型的值被圆整为字(word)或者双字(double-word),这样访问起来更迅速。
当声明一个结构类型时,可以包含关键字packed,这将对数据的存储进行压缩(并不是压缩,只是不再
圆整数据,而保留它的自然结构)。比如:
type TNumbers = packed array[1..100] of Real;
使用packed 使数据访问变慢,并且在使用字符数组的情况下,能影响类型兼容性
集合(Set)是同一种有序类型的值的聚集,它们包含的值没有内在的顺序,且一个值在集合中包含两次并没有
实际意义。声明:
type
TSomeInts = 1..250;
TIntSet = set of TSomeInts;
這等同於:type TIntSet = set of 1..250;
有了上面的声明,你就可以像下面这样构造集合了:
var Set1, Set2: TIntSet;
...
Set1 := [1, 3, 5, 7, 9];
Set2 := [2, 4, 6, 8, 10]
你也可以直接使用set of …构造直接声明变量:
var MySet: set of ’a’..’z’;
...
MySet := [’a’,’b’,’c’];
静态数组类型以下面的格式声明:array[indexType1, ..., indexTypen] of baseType
比如:var MyArray: array[1..100] of Char;
一个多维数组是数组的数组,比如:
type TMatrix = array[1..10] of array[1..50] of Real;
就等价于
type TMatrix = array[1..10, 1..50] of Real;
可使用这样的索引:MyMatrix[2,45],或像这样:MyMatrix[2][45]。
packed array[Boolean,1..10,TShoeSize] of Integer; 等价于
packed array[Boolean] of packed array[1..10] of packed array[TShoeSize] of Integer;
标准函数Low 和High 作用于数组类型(的标志符)或变量,它们返回数组第1 个索引(类型)的最小
值和最大值;Length 返回数组第1 维的元素个数
一维、压缩的(packed)、Char 类型的静态数组称为packed string,它和字符串类型兼容,也和其它具有
相同元素个数的packed string 兼容。
array[0..x] of Char 类型的数组,是0 下标开始的字符数组,它用来存储零结尾字符串,并且和PChar 类
型兼容。
給動態數組賦值或把它傳給SetLength函數時,它的內存被重新分配。
动态数组以下面的形式声明: array of baseType
比如:var MyFlexibleArray: array of Real;
要取消动态数组的分配,给它的变量赋值nil,或者把变量传给Finalize
不要对一个动态数组变量使用运算符‘^’,也不要对它使用New 或Dispose 过程
若X 和Y 是同一类型的动态数组变量,X := Y 使X 指向和Y 相同的数组(在这个操作之前,不必给X
分配内存)。不像字符串和静态数组,动态数组不会在被写之前自动拷贝。
使用索引给动态数组赋值(比如,MyFlexibleArray[2] := 7),不会为数组重新分配内存;编译时,索引
边界检查也不会给出提示。
要截断一个动态数组,把它传给SetLength 或Copy,并把返回的值赋给数组变量(SetLength 通常更快)
记录(类似于其它语言中的结构)表示不同种类的元素的集合,每个元素称为“字段”,声明记录类型时
要为每个字段指定名称和类型。声明记录的语法是
type recordTypeName = record
fieldList1: type1;
...
fieldListn: typen;
end
比如:
type
TDateRec = record
Year: Integer;
Month: (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
Day: 1..31;
end;
只有在实例化时才进行分配,像下面的样子:
var Record1, Record2: TDateRec;
Record2 := Record1; 把Record1 的值拷贝给Record2
也可以使用record ...构造直接声明变量:
var S: record
Name: string;
Age: Integer;
end;
一个记录类型能拥有变体部分,它看起来就像case 语句
type
TEmployee = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Salaried: Boolean of
True: (AnnualSalary: Currency);
False: (HourlyWage: Currency);
end;
要声明一个文件类型,使用下面的语法:type fileTypeName = file of type
--------------------------------------------------------------------------------
^符号有两个用途,在我们的例子中都用到了。当它出现在一个类型标志符前面时:
^typeName
它表示一个指向typeName 类型的变量的指针;当它出现在一个指针变量的后面时:
pointer^
它表示对指针解除引用,换句话说,它返回在指针所指向的地址处保存的值。
除了使用@运算符,你也可以使用几个标准例程给一个指针赋值。New 和GetMem 过程把一个内存地址
赋给指针,而Addr 和Ptr 函数则返回一个指向特定变量或地址的指针。
保留字nil 是一个特殊常量,可赋给任何指针(类型)。当nil 被赋给一个指针时,指针不表示任何东西。
使用下面的语法,你能声明一个任意类型的指针,
type pointerTypeName = ^type
当定义一个记录类型(或其它数据类型)时,习惯上也就定义了一个此类型的指针,这使得处理更容易,
我们不需要拷贝一大块内存。
在Pointer 类型变量的后面使用^运算符会引发编译错误。要访问一个Pointer 类型引用的变量,首先把它
转换为其它指针类型,然后再解除引用。
基本(fundamental)类型PAnsiChar 和PWideChar 分别表示AnsiChar 和WideChar 值的指针,一般(generic)
类型PChar 表示一个指向Char 的指针(在当前实现中,它表示AnsiChar)。这些字符指针用来操纵零结
尾字符串
System 和SysUtils 单元定义了许多常用的标准指针类型:
Pointer type Points to variables of type
PAnsiString,PString AnsiString
PByteArray TByteArray (declared in SysUtils).
Used to typecast dynamically allocated memory for array access.
PCurrency,PDouble,
PExtended,PSingle Currency,Double,Extended,Single
PInteger Integer POleVariant OleVariant
PShortString ShortString. Useful when porting legacy code that uses the old PString type.
PTextBuf TTextBuf (declared in SysUtils).
TTextBuf is the internal buffer type in a TTextRec file record.)
PVarRec TVarRec (declared in System)
PVariant Variant
PWideString WideString
PWordArray TWordArray (declared in SysUtils).
Used to typecast dynamically allocated memory for arrays of 2-byte values.
过程类型允许你把过程和函数作为“值”看待,它可以赋给变量或传给其它过程和函数。比如,假设你
定义了一个叫做Calc 的函数,它有两个整型参数并返回一个整数值:
function Calc(X,Y: Integer): Integer;
你可以把Calc 函数赋给变量F:
var F: function(X,Y: Integer): Integer;
F := Calc;
我们只取过程或函数头(heading)并把procedure 或function 后面的标志符去掉,剩下的就是过程类型
的名称。
可以在声明变量时直接使用这样的名称(就像上面的例子一样),也可以声明新类型:
type
TIntegerFunction = function: Integer;
TProcedure = procedure;
TStrProc = procedure(const S: string);
TMathFunc = function(X: Double): Double;
var
F: TIntegerFunction; {F 是一个无参数、返回整数值的函数}
Proc: TProcedure; { Proc 是一个无参数过程}
SP: TStrProc; { SP 是一个使用string 类型参数的过程}
M: TMathFunc; { M 是一个使用Double 类型参数、返回Double 值的函数}
procedure FuncProc(P: TIntegerFunction); { FuncProc 是一个过程,它的参数是一个无参数、返回整数值的函数}
上面的所有变量都是过程指针,也就是指向过程或函数地址的指针。若想引用一个实例对象的方法(参
考Classes and objects),你需要在过程类型的名称后面加上of object。比如
type
TMethod = procedure of object;
TNotifyEvent = procedure(Sender: TObject) of object;
这些类型表示方法指针。方法指针实际上是一对指针:第一个存储方法的地址,第二个存储方法所属的
对象的引用。给出下面的声明
type
TNotifyEvent = procedure(Sender: TObject) of object;
TMainForm = class(TForm)
procedure ButtonClick(Sender: TObject);
...
end;
var
MainForm: TMainForm;
onClick: TNotifyEvent
我们就可以进行下面的赋值:
onClick := MainForm.ButtonClick;
两个过程类型是兼容的,如果它们具有
一个程序包括:
• 一个程序头(program heading)
• 一个uses 子句(可选),和
• 一个包含声明和命令语句的块(block)
一个单元以单元头(unit heading)开始,后面跟interface、implementation、initialization
和finalization 部分,后面两个部分是可选的
一个uses 子句可以出现在:
• 程序或库的工程文件
• 单元的接口部分,和
• 单元的实现部分
在单元声明以及uses 子句中(尤其是在Linux 下),单元名称必须和文件名大小写一致。在其它情
况(比如使用限定符的标志符),单元名是大小写无关的。要避免在单元引用中出现问题,要明确指出单元文件:
uses MyUnit in "myunit.pas";
如果像上面这样在工程文件中明确引用一个单元,在其它源文件中就可以像下面那样简单地引用它,
而不必考虑大小写问题:
uses Myunit;
uses 子句给编译器提供各模块间的依赖信息,因为这些信息是存于模块自身的,所以,Object Pascal
程序不需要makefile 文件、头文件以及include 预处理指令(这些概念你可能要参考C 语言)。每当一个
工程调入IDE 时,Project Manager 创建一个makefile,但只有在包含多个工程的工程组中才保存这些文
件。
• 单元源文件 ( .pas)
• 工程文件 ( .dpr)
• 包源文件 ( .dpk)
• 窗体文件,扩展名为 .dfm(Delphi)或 .xfm(Kylix)
• 资源文件,扩展名为 .res (已经编译的资源文件)
• 工程选项文件,扩展名为 .dof(Delphi)或 .kof(Kylix)
要改变程序的图标,可使用Project Options 对话框。
<Leo> 在窗体设计器上右击弹出PopMenu有View as Text项,可察看事件和过程的关联
事件句柄通过窗体文件(Windows 下是 .dfm,Linux 下是 .xfm)赋给指定的事件
空格(#32)和控制符(#0 到#31,其中#13 叫回车符或行的结束符)被称为空白符(blank)。
特殊符号是非文字和数字字符,或这类字符的组合,它们有固定的意义。
‘[’相当于‘(.’,‘]’相当于‘.)’;‘(*’和‘*)’分别相当于‘{’和‘}’(表示注释)。
,!(惊叹号)、 ”(双引号)、 %(百分号)、 ?(问号)、 /(反斜杠)、 _(下划线)、 |(通道)和 ~(破折
号)不是特殊符号
$前缀表示一个16 进制数字,比如$8F
标签是一个不超过4 位的阿拉伯数字序列,也就是从0 到9999,打头的0 没有意义
。若单引号中没有内容(’’),它被称为空串(null string)。在一个引用串中,两个连续的单引号(’’)表示一个字 符,也就是单引号本身(’)控制串由一个或多个控制字符(控制符)所组成,每个控制符包含一个#,后跟一个无符号整数(10
进制或16 进制),整数的范围从0 到255,表示相应的ASCII 字符。下面的控制串
#89#111#117
就相当于引用串
’You’
运算符包括:@ not ^ * / div mod and shl shr as + - or xor = > < <> <= >= in 和 is。
一些运算符的行为因为传给它们的数据类型不同而不同。比如,not 运算符用于整数时,是对它的
位进行求反运算,而对布尔类型进行逻辑非运算。
除了 ^ ,is 和 in,其它运算可应用在Variant 类型上。
• 不管x 和y 的类型是什么,x/y 的结果总是扩展类型(extended);对其它运算符,只要有一个
运算数是实数类型,它的结果就是扩展类型;另外,只要有一个运算数是Int64 类型,它的结果就是Int64 类型;否则
,结果就是整数类型。如果一个运算数是整数的子界类型,它就像整数类型一样被对待。
• x div y 的值取整数,也就是取得x/y 的值,然后以0 的方向取得最近的整数。
• mod 运算返回对运算数进行整数除后得到的余数。换句话说,就是x mod y = x - (x div y)*y。
布尔运算符not、and、or 和xor 作用于任何布尔类型的运算数,并返回一个布尔类型的值。
使用 $B 编译器指示字控制计算方式,默认状态是 {$B-},它采用部分计算。要在局部进行完全计
算,在代码中使用 {$B+} 指示字。你也可以在Compiler Options 对话框中选择Complete Boolean
Evaluation 选项,此时在整个项目范围使用完全计算。
<Leo>///部分计算 equals 短路计算 in C++/C#
若任何一个运算数是variant 类型,编译器总是进行完全计算(即使在 {$B-} 状态下)
Logical (bitwise) operators(位逻辑运算符):not and or xor shl shr
• 位反(not)运算的返回类型和运算数相同;
• 若and、or 或xor 的运算数都是整数类型,则它的返回类型是包含运算数所有可能的值、且范围最小的预定义(内置)整数类型;• 运算 x shl y 和 x shr y 把 x 的值向左或向右移 y 个位,也就等同于 x 乘或除以 2^y(2的 y 次方),返回类型 和 x 相同。比如,若 N 存储的是01101(10 进制的13),那么 N shl 1 返11010(10 进制26)。注意,y 的值被解释为对 x 所属类型大小(位数)进行模运算,比如,若 x 是一个integer,x shl 40 被解释为 x shl 8,因为integer的大小是32 位(4字节),40 mod 32 等于8。
关系运算符 =、<>、<、>、<= 和 >= 都能对字符串进行操作 + 运算符连接两个字符串
• + 运算符的运算数可以是字符串、packed string(packed arrays of type Char)或字符。但是,若其中一个运算数
是宽字符(WideChar)类型,其它运算数必须是长字符串。
• + 运算符的返回结果和任何字符串类型是兼容的。但是,若运算数都是短字符串或字符,并且它们的组合长度大于255
,则返回结果取前面的255 个字符。
关系运算符 <、>、<= 和 >= 能对PChar 类型进行操作。其它的指运算符:+- 指针加减 ^ 取得指针所指的内容 = <>
等于 不等于
对于Pointer 类型,在dereference 之前必须进行类型转换。
• 若I 是一个整数,P 是一个字符指针,那么P + I 是把P 的地址加上I,也就是一个指向P 后面
第I 个字符处的指针(表达式I + P 等同于P + I);P – I 是把P 的地址减去I,也就是一个指向P
前面第I 个字符处的指针。
• 若P 和Q 都是字符指针,那么P – Q 计算P 的地址(高地址)和Q 地址(低地址)之差,也就
是返回一个表示P 和Q 之间字符数目的整数。P + Q 没有意义。
Set operators(集合运算符):
+并集 - 差集 * 交集 <= 小于等于(子集)>= 大于等于(超集) =等于 <>不等于 in 成员关系
以下规则适用于 +、– 和 * 运算符:
• 当且仅当序数(集合基础类型中的一个值)O 属于集合X 或集合Y(或同时属于X 和Y)时,
O 属于X + Y;当且仅当O 属于X 但不属于Y 时,O 属于X – Y;当且仅当O 同时属于X 和Y
时,O 属于X * Y。
• +、– 和 * 的运算结果属于集合类型set of A..B,这里A 是结果中的最小序数,B 是结果中的
最大序数。
以下规则适用于 <=、>=、=、<> 和 in 运算符:
• 只有当X(集合)中的每个成员也是Y(集合)中的成员时,X <= Y 才为真;Z >= W 等同于
W <= Z;只有当U(集合)和V(集合)正好拥有相同的成员时,U = V 才为真,否则U <> V
为真;
• 对于序数O 和集合S,只有当O 是S 的一个成员时,O in S 才为真。
• 除了实数和整数能一起比较外,两个运算数必须是兼容的类型;
• 对字符串进行比较,是依据它的每个字符在扩展ASCII 字符集中的顺序,字符类型被当作长度
为1 的字符串;
• 两个packed string 要进行比较,它们必须具有相同数目的元素;一个具有n 个元素的packed string
与一个字符串比较时,它被看作长度为n 的字符串;
• 只有当两个PChar 指针都指向同一个字符数组的范围内时,<、>、<= 和 >= 运算符才能作用
于它们;
• 运算符 = 和 <> 能以类或类引用类型作为运算数。当用于类类型时,= 和 <> 的计算规则与
指针一样,只有当C 和D 指向同一个实例对象时,C = D 为真,否则C <> D 为真;当用于类
引用时,只有当C 和D 表示同一个类时,C = D 为真,否则C <> D 为真。
as 和 is 运算符使用类和对象(实例)作为运算数,as 也用于接口类型。
@ 运算符返回一个变量、函数、过程或方法的地址,也就是说,@ 运算符构建一个指向运算数的
指针。
• 若X 是一个变量,@X 返回X 的地址(当X 是一个过程类型的变量时有特殊的规则,请参考语
句和表达式中的过程类型)。若默认的编译器指示字 {$T–} 在起作用,则@X 的类型是
Pointer(通用指针);在 {$T+} 状态下时,@X 的类型是 ^T,这里T 是X 的类型;
• 若F 是一个例程(一个函数或过程),@F 返回F 的入口点,@F 的类型总是Pointer;
• 当 @ 作用于类的方法时,必须使用类名来限定方法名。比如
@TMyClass.DoSomething
它指向TMyClass 的DoSomething 方法。
Set constructors(集合构造器)
[5, 6, 7, 8]
[ 5..8 ]
[red, green, MyColor]
[1, 5, 10..K mod 12, 23]
[’A’..’Z’, ’a’..’z’, Chr(Digit + 48)]
集合构造器[]表示空集
字符串、数组、数组属性以及指向字符串或数组的指针能被索引。比如:FileName[21]
强制类型转换的语法是
typeIdentifier(expression)
若表达式是一个变量,结果被称为variable typecast(变量转换);否则,结果是一个value typecast(值转换)。虽
然它们的语法相同,但它们有不同的转换规则。
在值转换中,类型标志符和转换的表达式必须都是有序类型或指针类型。值转换的例子包括
Integer(’A’)
Char(48)
Boolean(0)
Color(2)
Longint(@Buffer)
声明的语法以及声明的位置取决于要定义的标志符的种类。通常,声明只能出现在块(block)的开始处,
以及单元的接口或实现部分的开始处(在uses 子句之后)。
Hint 指示字platform、deprecated 和library 能附加在任何声明之后。在声明过程或函数的情况下,应
使用分号把hint 指示字和声明的其它部分分开。比如:
procedure SomeOldRoutine; stdcall; deprecated;
var VersionNumber: Real library;
type AppError = class(Exception)
...
end platform;
当源代码在{$HINTS ON} {$WARNINGS ON}状态下编译时,对使用上述指示字声明的标志符的每个引
用都将产生一个适当的提示或警告。使用platform 标记一个条目和特定的操作系统(比如Windows 和
Linux)相关;使用deprecated 表示条目已经废弃或支持它仅为了向后兼容性;使用library 表示依赖于
特定的库或组件框架(比如VCL 或CLX)。
赋值语句的格式如下
variable := expression
这里,variable 是任何变量引用,包括变量、变量类型转换、解除引用的指针,或者一个结构变量的组
成部分;expression 是任何一个赋值兼容的表达式。(在函数块中,variable 能被函数名取代,参考Procedures
and functions。
当启用扩展语法时({$X+}),调用函数也可以像调用过程那样 当这样调用函数时,它的返回值被忽略。
goto label
label: statement
label label;
label label1, ..., labeln;
• 复合语句或with 语句只是简单地执行一系列语句;
• 条件语句,也就是if 或case 语句,根据指定的标准,最多执行一个分支;
• 循环语句,包括repeat、while 和for 循环,重复执行一系列语句;
• 一组特殊的语句,包括raise、try...except 和try...finally 结构,用来创建和处理异常。
with 语句的语法是
with obj do statement
或
with obj1, ..., objn do statement
if 语句有两种形式:if...then 和if...then...else
比如,
if J = 0 then
Exit
else
Result := I/J;
if J <> 0 then
begin
Result := I/J;
Count := Count + 1;
end
else if Count = Last then
Done := True
else
Exit;
Case Statements(Case 语句):
case selectorExpression of
caseList1: statement1;
...
caseListn: statementn;
else
statements;
end
case I of
1..5: Caption := ’Low’;
6..9: Caption := ’High’;
0, 10..99: Caption := ’Out of range’;
else
Caption := ’’;
end;
selectorExpression 是任何一个有序类型的表达式(字符串无效),和C++一样的。
。Object Pascal 有三种循环:repeat 语句、while 语句和for 语句。
使用Break 和Continue 过程来控制repeat、while 或for 语句的流程。
repeat 语句的语法是
repeat statement1; ...; statementn; until expression
比如:
repeat
Write(’Enter a value (0..9): ’);
Readln(I);
until (I >= 0) and (I <= 9);
while 语句的语法是
while expression do statement
比如:
while I > 0 do
begin
if Odd(I) then Z := Z * X;
I := I div 2;
X := Sqr(X);
end;
for 语句的语法是
for counter := initialvalue to finalvalue do statement
或
for counter := initialvalue downto finalvalue do statement
比如:for C := Red to Blue do Check(C);
一个块包含一系列的声明,后面跟一个符合语句。所有的声明必须一起出现在块的开始处,所以,块的
形式是
declarations;
begin
statements;
end;
比如:
function UpperCase(const S: string): string;
var
Ch: Char;
L: Integer;
Source, Dest: PChar;
begin
...
end;
类型可以分为基本(fundamental)和一般(generic)类型。基本类型的范围和形式是相同的,不管是基于何种CPU 和
操作系统;而一般类型的范围和形式是平台相关的
大多数内置类型属于基本类型,但少数整数、字符、字符串和指针类型属于一般类型。
在需要的时候使用一般数据类型是一个好注意,因为它们提供优化的性能和轻便性。
类型也可以分为简单类型、字符串类型、结构类型、指针类型、过程类型和变体类型。
下面的提纲显示了Object Pascal 数据类型的分类:
simple简单类型
ordinal有序类型
integer 一般(generic)整数类型是Integer 和Cardinal
基本整数类型包括Shortint、Smallint、Longint、
Int64、Byte、Word 和Longword
character 基本字符类型是AnsiChar 和WideChar。
一般字符类型是Char,它相当于AnsiChar。
Boolean 布尔类型为Boolean、ByteBool、WordBool和LongBool,Boolean是首选的
enumerated
subrange
real实数类型 Real48 Single Double Extended Comp Currency
string 字符串类型 ShortString AnsiString WideString
structured
set
array
record
file
class
class reference
interface
pointer
procedural
Variant
(type identifier)
标准函数SizeOf 作用于所有变量和类型标志符,它返回一个整数,表明存储指定类型的数据所需要的内存数(字节)。
有序类型包括整数、字符、布尔、枚举和子界类型。有序类型定义一个有次序的数值集合,除了它的第一个值以外,其它每个值都有一个唯一的前驱值(predecessor);除了最后一个外,其它每个值都有一个唯一的后继值(successor)
Ord 有序类型表达式 序数值
Pred 有序类型表达式 表达式的前驱值
Succ 有序类型表达式 表达式的后继值
High 有序类型的变量或标志符 类型的最大值
Low 有序类型的变量或标志符 类型的最小值
例程High、Low、Succ、Pred、Inc、Dec、IntToStr 和IntToHex 完全支持Int64 参数。
而且,Round、Trunc、StrToInt64 和StrToInt64Def 返回Int64 类型的值;
少数例程(包括Ord)根本不能对Int64 数值进行操作。
当把整数类型的最后一个值增大或把第一个值减少时,结果将回到整数类型的开头或尾部
。内置函数Chr,返回一个在AnsiChar 或WideChar取值范围内任意一个整数的字符值。比如,Chr(65)返回字母A。
<Leo>Inc()是什么呢?
对ByteBool、WordBool 和LongBool 来说,若它的序数不为0,它就被认为是True。在一个需要Boolean类型的环境种,
编译器自动把非0 值转换为True。
在Object Pascal 中,布尔表达式不能和整数或实数进行换算。所以,若X 是一个整数变量,语句
if X then ...;
会产生编译错误
定义一个枚举类型,使用下面的语法:
type typeName = (val1, ..., valn)
type Size = (Small = 5, Medium = 10, Large = Small + Medium);
比如:type Suit = (Club, Diamond, Heart, Spade);
在声明变量时,可以直接使用(val1,…,valn)结构,它就像一个类型名称:
var MyCard: (Club, Diamond, Heart, Spade);
子界类型表示其它有序类型(称为基础类型)的一个子集:它的形式为Low..High
• Extended 类型比其它实数类型有更高的精度,但不够轻巧。当使用Extended 类型创建的文件要跨平
台共享时,务必小心。
• Comp(computational)类型对Intel CPU 是优化的,表示为64 位整数,但它被分类位实数类型,因为它的行为不像有序类型(比如,你不能递增和递减)。保留此类型只是为了向后兼容性,使用Int64可获得更好的性能。
• Currency 类型有固定的小数点,可以把在货币运算中出现的错误减到最少。It is stored as a scaled
64-bit integer with the four least significant digits implicitly representing decimal places. 当在赋值
语句和表达式中与其它实数类型混合使用时,它的值会自动除以或乘上10000。
在赋值语句和表达式中,字符串类型可以混合使用,编译器自动进行所需的转换。但对于过程或函数,
当使用引用方式传递字符串时,类型必须正确。
在默认的{$H+}状态下,编译器把string(当它的后面没有包含数字的中括号时)解释为AnsiString;
使用{$H-}指示字把它解释为ShortString。
标准函数Length 返回一个字符串的字符个数;SetLength 设置一个字符串的长度。
可以像数组一样对字符串使用索引。若S 是一个字符串变量,i 是一个整数表达式,则S[i]表示S 中第
i 个字符(或者,严格说来,是第i 个字节)。对于ShortString 或AnsiString,S[i]是AnsiChar 类型;对于
WideString,S[i]是WideChar 类型。语句 MyString[2] := ’A’; 把值A 赋给MyString 的第2 个字符。
若S 是一个ShortString 变量,Ord(S[0]),和Length(S)一样,将返回S 的长度;给S[0]赋值,就像调用SetLength
,将改变S 的长度。
var MyString: string[100];声明一个叫做MyString 的变量,它的最大长度是100 字节,
标准函数High 和Low 能作用于short-string 类型名和变量,High 返回它的最大长度,Low 返回0。
AnsiString 类型又称为长字符串,它可以动态分配,并且长度只受内存限制。它使用8 位ANSI 字符。
长串变量是一个指针,占据4 个字节的内存。当变量为空时(也就是长度为0 的字符串),指针为nil,
此时,它不需要额外的内存
因为长串变量是指针,所以,两个或更多的变量可以引用同一个值,而不必使用额外的内存。编译器利
用这一点节省资源和进行快速赋值。只要一个长串变量被销毁或赋给一个新值,原来的串(变量的前一
个值)引用计数减1,而新的值(如果有的话)引用计数加1。若引用计数为0,它的内存被释放。这个
过程被称为reference-counting。当使用字符串索引改变其中的一个字符时,若字符串的引用计数大于1,
将生成串的一个拷贝,这被称为copy-on-write 机制。
WideString 类型是动态分配的、由16 位Unicode 字符所构成的字符串。在大多数方面,它和AnsiString
相似。(注:宽字符串没有引用计数,不支持copy-on-write 机制,但支持内存动态分配。)
在Win32 下,WideString 和COM BSTR 类型兼容。
Object Pascal 支持单字节和多字节字符以及字符串,适用的类型有:Char、PChar、AnsiChar、PAnsiChar
和AnsiString。对多字节字符串使用索引是不可取的,因为S[i]表示S 中第i 个字节(不一定是第i 个字
符),但是,标准字符串处理函数有多字节版本,它们还实现了locale-specific ordering for characters(多
字节函数的名称通常以Ansi 开头,比如StrPos 的多字节版本是AnsiStrPos)。多字节支持依赖于操作系
统和本地设置(current locale)。
Object Pascal 使用WideChar、PWideChar 和WideString 类型支持Unicode 字符和字符串。
字符串常量和类型PChar、PWideChar 是赋值兼容的,后两者表示指针,
它们指向一个以0 结尾的Char 或WideChar 字符数组。
一个字符指针(PChar 或PWideChar)可以像数组一样使用索引。
结构类型包括集合、数组、记录,也包括类、类引用(class-reference)和接口类型。
除了集合只能包含有序值以外,结构类型可以包含其它的结构类型,且结构的层次不受限制。
默认情况下,一个结构类型的值被圆整为字(word)或者双字(double-word),这样访问起来更迅速。
当声明一个结构类型时,可以包含关键字packed,这将对数据的存储进行压缩(并不是压缩,只是不再
圆整数据,而保留它的自然结构)。比如:
type TNumbers = packed array[1..100] of Real;
使用packed 使数据访问变慢,并且在使用字符数组的情况下,能影响类型兼容性
集合(Set)是同一种有序类型的值的聚集,它们包含的值没有内在的顺序,且一个值在集合中包含两次并没有
实际意义。声明:
type
TSomeInts = 1..250;
TIntSet = set of TSomeInts;
這等同於:type TIntSet = set of 1..250;
有了上面的声明,你就可以像下面这样构造集合了:
var Set1, Set2: TIntSet;
...
Set1 := [1, 3, 5, 7, 9];
Set2 := [2, 4, 6, 8, 10]
你也可以直接使用set of …构造直接声明变量:
var MySet: set of ’a’..’z’;
...
MySet := [’a’,’b’,’c’];
静态数组类型以下面的格式声明:array[indexType1, ..., indexTypen] of baseType
比如:var MyArray: array[1..100] of Char;
一个多维数组是数组的数组,比如:
type TMatrix = array[1..10] of array[1..50] of Real;
就等价于
type TMatrix = array[1..10, 1..50] of Real;
可使用这样的索引:MyMatrix[2,45],或像这样:MyMatrix[2][45]。
packed array[Boolean,1..10,TShoeSize] of Integer; 等价于
packed array[Boolean] of packed array[1..10] of packed array[TShoeSize] of Integer;
标准函数Low 和High 作用于数组类型(的标志符)或变量,它们返回数组第1 个索引(类型)的最小
值和最大值;Length 返回数组第1 维的元素个数
一维、压缩的(packed)、Char 类型的静态数组称为packed string,它和字符串类型兼容,也和其它具有
相同元素个数的packed string 兼容。
array[0..x] of Char 类型的数组,是0 下标开始的字符数组,它用来存储零结尾字符串,并且和PChar 类
型兼容。
給動態數組賦值或把它傳給SetLength函數時,它的內存被重新分配。
动态数组以下面的形式声明: array of baseType
比如:var MyFlexibleArray: array of Real;
要取消动态数组的分配,给它的变量赋值nil,或者把变量传给Finalize
不要对一个动态数组变量使用运算符‘^’,也不要对它使用New 或Dispose 过程
若X 和Y 是同一类型的动态数组变量,X := Y 使X 指向和Y 相同的数组(在这个操作之前,不必给X
分配内存)。不像字符串和静态数组,动态数组不会在被写之前自动拷贝。
使用索引给动态数组赋值(比如,MyFlexibleArray[2] := 7),不会为数组重新分配内存;编译时,索引
边界检查也不会给出提示。
要截断一个动态数组,把它传给SetLength 或Copy,并把返回的值赋给数组变量(SetLength 通常更快)
记录(类似于其它语言中的结构)表示不同种类的元素的集合,每个元素称为“字段”,声明记录类型时
要为每个字段指定名称和类型。声明记录的语法是
type recordTypeName = record
fieldList1: type1;
...
fieldListn: typen;
end
比如:
type
TDateRec = record
Year: Integer;
Month: (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
Day: 1..31;
end;
只有在实例化时才进行分配,像下面的样子:
var Record1, Record2: TDateRec;
Record2 := Record1; 把Record1 的值拷贝给Record2
也可以使用record ...构造直接声明变量:
var S: record
Name: string;
Age: Integer;
end;
一个记录类型能拥有变体部分,它看起来就像case 语句
type
TEmployee = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Salaried: Boolean of
True: (AnnualSalary: Currency);
False: (HourlyWage: Currency);
end;
要声明一个文件类型,使用下面的语法:type fileTypeName = file of type
--------------------------------------------------------------------------------
^符号有两个用途,在我们的例子中都用到了。当它出现在一个类型标志符前面时:
^typeName
它表示一个指向typeName 类型的变量的指针;当它出现在一个指针变量的后面时:
pointer^
它表示对指针解除引用,换句话说,它返回在指针所指向的地址处保存的值。
除了使用@运算符,你也可以使用几个标准例程给一个指针赋值。New 和GetMem 过程把一个内存地址
赋给指针,而Addr 和Ptr 函数则返回一个指向特定变量或地址的指针。
保留字nil 是一个特殊常量,可赋给任何指针(类型)。当nil 被赋给一个指针时,指针不表示任何东西。
使用下面的语法,你能声明一个任意类型的指针,
type pointerTypeName = ^type
当定义一个记录类型(或其它数据类型)时,习惯上也就定义了一个此类型的指针,这使得处理更容易,
我们不需要拷贝一大块内存。
在Pointer 类型变量的后面使用^运算符会引发编译错误。要访问一个Pointer 类型引用的变量,首先把它
转换为其它指针类型,然后再解除引用。
基本(fundamental)类型PAnsiChar 和PWideChar 分别表示AnsiChar 和WideChar 值的指针,一般(generic)
类型PChar 表示一个指向Char 的指针(在当前实现中,它表示AnsiChar)。这些字符指针用来操纵零结
尾字符串
System 和SysUtils 单元定义了许多常用的标准指针类型:
Pointer type Points to variables of type
PAnsiString,PString AnsiString
PByteArray TByteArray (declared in SysUtils).
Used to typecast dynamically allocated memory for array access.
PCurrency,PDouble,
PExtended,PSingle Currency,Double,Extended,Single
PInteger Integer POleVariant OleVariant
PShortString ShortString. Useful when porting legacy code that uses the old PString type.
PTextBuf TTextBuf (declared in SysUtils).
TTextBuf is the internal buffer type in a TTextRec file record.)
PVarRec TVarRec (declared in System)
PVariant Variant
PWideString WideString
PWordArray TWordArray (declared in SysUtils).
Used to typecast dynamically allocated memory for arrays of 2-byte values.
过程类型允许你把过程和函数作为“值”看待,它可以赋给变量或传给其它过程和函数。比如,假设你
定义了一个叫做Calc 的函数,它有两个整型参数并返回一个整数值:
function Calc(X,Y: Integer): Integer;
你可以把Calc 函数赋给变量F:
var F: function(X,Y: Integer): Integer;
F := Calc;
我们只取过程或函数头(heading)并把procedure 或function 后面的标志符去掉,剩下的就是过程类型
的名称。
可以在声明变量时直接使用这样的名称(就像上面的例子一样),也可以声明新类型:
type
TIntegerFunction = function: Integer;
TProcedure = procedure;
TStrProc = procedure(const S: string);
TMathFunc = function(X: Double): Double;
var
F: TIntegerFunction; {F 是一个无参数、返回整数值的函数}
Proc: TProcedure; { Proc 是一个无参数过程}
SP: TStrProc; { SP 是一个使用string 类型参数的过程}
M: TMathFunc; { M 是一个使用Double 类型参数、返回Double 值的函数}
procedure FuncProc(P: TIntegerFunction); { FuncProc 是一个过程,它的参数是一个无参数、返回整数值的函数}
上面的所有变量都是过程指针,也就是指向过程或函数地址的指针。若想引用一个实例对象的方法(参
考Classes and objects),你需要在过程类型的名称后面加上of object。比如
type
TMethod = procedure of object;
TNotifyEvent = procedure(Sender: TObject) of object;
这些类型表示方法指针。方法指针实际上是一对指针:第一个存储方法的地址,第二个存储方法所属的
对象的引用。给出下面的声明
type
TNotifyEvent = procedure(Sender: TObject) of object;
TMainForm = class(TForm)
procedure ButtonClick(Sender: TObject);
...
end;
var
MainForm: TMainForm;
onClick: TNotifyEvent
我们就可以进行下面的赋值:
onClick := MainForm.ButtonClick;
两个过程类型是兼容的,如果它们具有