Delphi / Pascal 语法知识干货

时间:2023-11-24 11:45:26

********************************************
* Pascal、Delph干货 *
********************************************

一、Pascal与Delphi
Delphi 中是使用的是面向对象的Pascal编程语言

二、Pascal编码
1.注释:
Pascal中的代码注释:{content}、(* content *)
Delphi中也支持C++注释: //content

2.大小写问题:
Pascal中不区分大小写

3.Pascal运算符
@ 取变量地址(返回一个指针)
not 逻辑取反或按位取反
/ 浮点数相除
div 整数相除
shl 按位左移
shr 按位右移
= 判断是否相等
<> 判断是否不相等
in 判断是否是集合成员
is 判断对象是否类型兼容(又一个RTTI运算符)

4.变量(Pascal中变量是先声明在使用,和C系列语系一致)
变量声明:
var
Value: Integer;
i,j: Char;
IsCorrect: Boolean;

变量简单赋值:
Value := 10;
IsCorrect := True;

Delphi语法:
全程变量://下面这种只能用于全程变量,不能用于过程或方法的变量。
var
Value: Integer = 10;
Correct: Boolean = True;
5.常量
Pascal语法:
const
Thousand = 1000;
Pi = 3.14;
AuthorName = 'Marco Canto';
(* 上面这些常量编译器会做一个隐式转换 *)
Delphi语法:
const
Thousand: Integer = 1000;
6.资源串(字符串)常量
Delphi 3 之前:
const
AuthorName = 'Marco canto'

Delphi 3 之后:
resourcestring
AuthorName = 'Marco Canto';
BookName = 'Essential Pascal';
7.数据类型
Pascal:有序数据、实数、字符串类型
Delphi:在Pascal之上多一种 无类型可变数据类型(variant)

三、自定义数据类型
1.命名及不命名的类型
type //type代码区
……
end
2.子界类型(subRange)
type
Ten = 1..10;
OverHundred = 100..1000;
Uppercase = 'A'..'Z';
3.枚举类型
type
Color = (Red,Yello,Green,Cyan,Blue,Violet);
4.集合类型
type
Letters = set of Uppercase;

用上面定义的类型定义变量
var
Letters1,Letters2,Letters3: Letters;
begin
Letters1 := ['A','B','C'];
Letters2 := ['K'];
Letters3 := [];
5.数组类型
type
DayTemperatures = array [1..24] of Integer;
var
DayTemp1: Daytemperatures;
procedure AssignTemp;
begin
DayTemp1 [1] := 54;
DayTemp1 [2] := 52;
...
DayTemp1 [23] := 64;
DayTemp1 [24] := 60;//这里不要越界哟!语法和C/C++ 语法差不多,不是不能访问编译器不允许我们这么做,这是非法访问内存

多维数组:
type
MonthTemps = array [1..24,1..31] of Integer;
YearTemps = array[1..24,1..31,Jan..Dec] of Integer;
var
ThisYear: YearTemps;
begin
...
ThisYear[Feb] := ThisYear[Jan];
6.记录类型(这个类型就和C语言体系中Struct 是一致的)
type
Date = record
Year: Integer;
Month: Byte;
Day: Byte;
end;
var
BirthDay: Date;
begin
BirthDay.Year := 1997;
BirthDay.Month := 2;
BirthDay.Day := 14;

7.指针(C(C++)中*(指针),&(取地址) Pascal(Delphi)中 ^(指针),@(取地址))
type
PointerToInt = ^Integer;
var
P: ^Integer;
X: Integer;
begin
P := @X; //P->X 指针P指向X 这块儿内存
X := 10;
P^ := 20;//注意,这里的和C中解地址的书写方式不一样,C(C++)语言中*在变量名之前,Pascal(Delphi)中^在变量名之后
8.文件类型
type
IntFile = file of Integer;//这里就是C语言中的文件描述符(int) 只是方便文件的查找,文件的管理
注意:
Pascal 文件类型的使用很直观,而且Delphi 中也定义了一些控件用于文件保存和装载,以及对数据流和数据库的支持。

四、语句
1.简单语句与复合语句
X := Y + Z;
A := B;
2.赋值语句
A := 10;
3.条件语句
if 语句 -> if 语句可以嵌套
procedure TForm1.Button1Click(Sender: TObject);
begin
if CheckBox1.Checked then
ShowMessage ('CheckBox1 is checked')
else
ShowMessage ('CheckBox2 is not checked');
end;

case语句
case Number of
1: Text := 'One';
2: Text := 'Two';
3: Text := 'Three';
end;

case MyChar of
'+' : Text := 'Plus sign';
'-' : Text := 'Minus sign';
'*','/' : Text := 'Multiplication or division';
'0'..'9' : Text := 'Number';
'a'..'z' : Text := 'Lowercase character';
'A'..'Z' : Text := 'Uppercase character';
else
Text := 'Unknown character';
end;

五、循环语句
1.for 循环
for ... to ... do 语句
var
K,I:Integer;
begin
K := 0;
for I := 1 to 10 do
K := K + I;

for ... downto ... do 语句
var
K, I: Integer;
begin
K := 0;
for I := 10 downto 1 do
K := K + I;

2.while 和 repeat-until(C 语言中 do{} while) 语句(这两者差别不大)
while (I <= 100) and (J <= 100) do
begin
// use I and J to compute something...
I := I + 1;
J := J + 1;
end;

repeat //该语句至少做一次操作
// use I and J to compute something ...
I := I + 1;
J := J + 1;
until (I > 100) or (J > 100);

3.with 语句
With语句是一种用于简化代码的语句。 如你要访问一个记录类型变量(或一个对象),用With语句就不必每次重复变量的名字。例如对于以下的记录类型代码:

type
Date = record
Year: Integer;
Month: Byte;
Day: Byte;
end;

var
BirthDay: Date;

begin
BirthDay.Year := 1997;
BirthDay.Month := 2;
BirthDay.Day := 14;

可以用with语句改进后半部分代码,如下:

begin
with BirthDay do
begin
Year := 1995;
Month := 2;
Day := 14;
end;

六、Pascal 过程与函数
1.过程与函数:
Pascal中的例程有两种形式:过程和函数。理论上说,过程是你要求计算机执行的操作,函数是能返回值的计算。两者突出的不同点在于:函数能返回计算结果,即有一个返回值,而过程没有。两种类型的例程都可以带多个给定类型的参数。

不过实际上函数和过程差别不大,因为你可以调用函数完成一系列操作,跳过其返回值(用可选的出错代码或类似的东西代替返回值);也可以通过过程的参数传递计算结果(这种参数称为引用,下一部分会讲到)。

下例定义了一个过程、两个函数,两个函数的语法略有不同,结果是完全相同的。

procedure Hello;
begin
ShowMessage ('Hello world!');
end;

function Double (Value: Integer) : Integer;
begin
Double := Value * 2;
end;

// or, as an alternative
function Double2 (Value: Integer) : Integer;
begin
Result := Value * 2;
end;
流行的做法是用Result 给函数赋返回值,而不是用函数名,我认为这样的代码更易读。

一旦定义了这些例程,你就可以多次调用,其中调用过程可执行操作;调用函数能计算返回值。如下:

procedure TForm1.Button1Click (Sender: TObject);
begin
Hello;
end;

procedure TForm1.Button2Click (Sender: TObject);
var
X, Y: Integer;
begin
X := Double (StrToInt (Edit1.Text));
Y := Double (X);
ShowMessage (IntToStr (Y));
end;

2.引用参数
Pascal 例程的传递参数可以是值参也可以是引用参数。值参传递是缺省的参数传递方式:即将值参的拷贝压入栈中,例程使用、操纵的是栈中的拷贝值,不是原始值。

当通过引用传递参数时,没有按正常方式把参数值的拷贝压栈(避免拷贝值压栈一般能加快程序执行速度),而是直接引用参数原始值,例程中的代码也同样访问原始值,这样就能在过程或函数中改变参数的值。引用参数用关键字var 标示。

参数引用技术在大多数编程语言中都有,C语言中虽没有,但C++中引入了该技术。在C++中,用符号 &表示引用;在VB中,没有ByVal 标示的参数都为引用。

下面是利用引用传递参数的例子,引用参数用var关键字标示:

procedure DoubleTheValue (var Value: Integer);
begin
Value := Value * 2;
end;
在这种情况下,参数既把一个值传递给过程,又把新值返回给调用过程的代码。当你执行完以下代码时:

var
X: Integer;
begin
X := 10;
DoubleTheValue (X);
x变量的值变成了20,因为过程通过引用访问了X的原始存储单元,由此改变了X的初始值。

3.常量参数
除了引用参数外,还有一种参数叫常量参数。由于不允许在例程中给常量参数赋新值,因此编译器能优化常参的传递过程。编译器会选用一种与引用参数相似的方法编译常参(C++术语中的常量引用),但是从表面上看常参又与值参相似,因为常参初始值不受例程的影响。

事实上,如果编译下面有点可笑的代码,Delphi将出现错误:

function DoubleTheValue (const Value: Integer): Integer;
begin
Value := Value * 2; // compiler error,const 修饰Value 该变量就不能再被修改
Result := Value;
end;

4.开放数组参数
与C语言不同,Pascal 函数及过程的参数个数是预定的。如果参数个数预先没有确定,则需要通过开放数组来实现参数传递。

一个开放数组参数就是一个固定类型开放数组的元素。 也就是说,参数类型已定义,但是数组中的元素个数是未知数。见下例:

function Sum (const A: array of Integer): Integer;
var
I: Integer;
begin
Result := 0;
for I := Low(A) to High(A) do
Result := Result + A[I];
end;

上面通过High(A)获取数组的大小,注意其中函数返回值 Result的应用, Result用来存储临时值。你可通过一个整数表达式组成的数组来调用该函数:

X := Sum ([10, Y, 27*I]);

5.Delphi 调用协定
32位的Delphi 中增加了新的参数传递方法,这里的调用协定 和Win32 中stdcall或者callback 类似

6.Forward 声明(函数声明)

当使用一个标识符(任何类型)时,编译器必须已经知道该标识符指的是什么。为此,你通常需要在例程使用之前提供一个完整的声明。然而在某些情况下可能做不到这一点,例如过程A调用过程B,而过程B又调用过程A,那么你写过程代码时,不得不调用编译器尚未看到其声明的例程。

欲声明一个过程或函数,而且只给出它的名字和参数,不列出其实现代码,需要在句尾加forward 关键字:

procedure Hello; forward;

7. 方法(类中的过程或函数)

8. 函数重载
重载的思想很简单:编译器允许你用同一名字定义多个函数或过程,只要它们所带的参数不同。实际上,编译器是通过检测参数来确定需要调用的例程。

下面是从VCL的数学单元(Math Unit)中摘录的一系列函数:

function Min (A,B: Integer): Integer; overload;
function Min (A,B: Int64): Int64; overload;
function Min (A,B: Single): Single; overload;
function Min (A,B: Double): Double; overload;
function Min (A,B: Extended): Extended; overload;
当调用方式为Min (10, 20)时,编译器很容易就能判定你调用的是上列第一个函数,因此返回值也是个整数。

声明重载函数有两条原则:

每个例程声明后面必须添加overload 关键字。
例程间的参数个数或(和)参数类型必须不同,返回值不能用于区分各例程。

9.缺省参数
Delphi 4 中添加了一个新功能,即允许你给函数的参数设定确省值,这样调用函数时该参数可以加上,也可以省略。下例把应用程序全程对象的MessageBox 方法重新包装了一下,用PChar 替代字符串,并设定两个确省值:

procedure MessBox (Msg: string;
Caption: string = 'Warning';
Flags: LongInt = mb_OK or mb_IconHand);
begin
Application.MessageBox (PChar (Msg),
PChar (Caption), Flags);
end;
使用这一定义,你就可以用下面任一种方式调用过程:

MessBox ('Something wrong here!');
MessBox ('Something wrong here!', 'Attention');
MessBox ('Hello', 'Message', mb_OK);

七、字符串操作

1.字符串有char、string 和 wchar、String(长字符串)
2.格式化字符串
Format('First %d,Second %d',[n1,n2]); //占位符%d
Format('%8d',[n1]); //该句把数字你n1转换成有8个字符的字符串,并通过填充空白使文本右对齐(+),左对齐(-)
Pascal 中 Format函数的占位符
d,x,s,g ...

八、内存

1.Delphi 4 动态数组
procedure TForm1.Button1Click(Sender: TObject);
var
Array1: array of Integer;
begin
Array1 [1] := 100; // error
SetLength (Array1, 100);
Array1 [99] := 100; // OK
...
end;

九、Windows 编程
在此模块采用Window(窗口化)编程可以避免一些VCL库一些错误,所以当有必要的时候可以采用 此模块进行绕开技术

十、程序和单元
1.单元(unit)
unit Unit1;

interface

implementation

end.
单元的概念比较简单,单元名与文件名相同,而且必须唯一。单元包括界面区(interface)及实现区(implementation),界面区用于声明其它单元能看到的部分;实现区存放界面的实现代码及外部不可见的声明。此外还有两个可选的区,即初始化区及结束区,其中初始化区存放初始化代码,当程序加载到内存时执行;结束区存放程序终止时执行的代码。

单元总体结构如下:

unit unitName;

interface

// other units we need to refer to
uses //需要访问的外部单元
A, B, C;

// exported type definition
type
newType = TypeDefinition;

// exported constants
const
Zero = 0;

// global variables
var
Total: Integer;

// list of exported functions and procedures
procedure MyProc;

implementation

uses
D, E;

// hidden global variable
var
PartialTotal: Integer;

// all the exported functions must be coded
procedure MyProc;
begin
// ... code of procedure MyProc
end;

initialization
// optional initialization part

finalization
// optional clean-up code

end.