记录
记录
记录的定义
记录相当于 C 语言的结构体,定义例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| type TMyDateRecord = record year: Integer; month: Integer; day: Integer; end;
var myBirthDay : TMyDateRecord;
begin myBirthDay.year := 2002; myBirthDay.month := 3; myBirthDay.day := 9; end;
|
记录赋值
- 记录赋值,可以各个成员单独逐个进行赋值
- 记录类型的变量可以直接赋值给另一个相同类型的记录
1 2 3
| var myBirthDay1, myBirthDay2 : TMyDateRecord;
myBirthDay1 := myBirthDay2;
|
变体记录
变体记录的作用相当于 C 语言的 union,可以多个字段共用一段重复的内存空间,避免浪费。
变体记录的声明格式是:
1 2 3 4 5 6 7 8 9 10 11
| type 记录类型名 = record 字段1 : 类型1; 字段2 : 类型2; ... case [tag:] 有序类型 of 常量1: ( 字段声明列表1 ); 常量2: ( 字段声明列表2 ); 常量3: ( 字段声明列表3 ); ... end;
|
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| type TMyRecord1 = record value1: Integer; value2: Integer; case Integer of 1: (value3: Integer); 2: ( value4: Integer; value5: Integer; ); 3, 4: (value5: Double) end;
var vrecord : TMyRecord1; begin vrecord.value5 := 8; end.
|
- case 前为记录的固定部分
- case 后的部分为变体部分,一直到 end 结束
- 变体部分的大小由里面占用空间最大的部分决定
- 变体部分的每个 case 常量值占用的空间是共用的
- 最后一次 case 常量值的声明的部分的分号可以省略
- case 没有对应的 end,最后的 end 是跟 record 对应的
- tag 可选声明,如果有声明的话,可以作为记录的一个字段
- 有声明 tag 时,记录中 tag 会多占用一个 tag 类型的空间
- 变体中,不可以存在长字符串、动态数组、变体、接口等类型或衍生类型
SizeOf
SizeOf 内置函数可以获得记录占用的大小。可以传递记录的类型名,也可以传递记录的变量名
packed record
packed record 一共成为压缩记录,它会忽略字段对齐,把字段压缩成最小的记录。
1 2 3 4 5 6
| type 记录类型名 = packed record 字段1 : 类型1; 字段2 : 类型2; .... end;
|
记录的封装
可以声明 private 和 public 部分,将记录封装。
不同于类:
- private 部分内的字段,在本 unit 单元内可以访问,外部单元则不可访问。
- public 部分内的字段,在本 unit 单元和外部单元都可以访问。
1 2 3 4 5 6 7 8 9 10 11
| type TMyRecord = record private inner1: Integer; inner2: Integer; inner3: Integer; public pub1: Integer; pub2: Integer; pub3: Integer; end;
|
带方法的记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| type TMyRecord = record private inner1: Integer; inner2: Integer; inner3: Integer; public procedure SetInner1(v: Integer); function GetInner1: Integer; end;
procedure TMyRecord.SetInner1(v: Integer); begin inner1 := v; end;
function TMyRecord.GetInner1: Integer; begin Result := inner1 end;
|
Self
Self 是一个隐藏的记录引用。调用记录中的方法,会隐藏传递一个本记录实例的引用,叫做 Self
。
构造器
构造器用于记录初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| type TMyRecord = record private inner1: Integer; public constructor Create (newValue: Integer); end;
constructor TMyRecord.Create (newValue: Integer); begin inner1 := newValue; end;
var rec1, rec2 : TMyRecord;
rec1 := TMyRecord.Create(100); rec2.Create(200);
|
记录的构造器必须带有参数,不允许不带参数,否则编译错误。
托管记录
记录的初始化还有另外一种方式:托管记录。
当记录只具有普通(非托管)字段时,编译器不需要做太多操作。
当记录中包含了长字符串、接口、动态数组、变体等托管类型时,它就是托管记录。编译器会在托管记录使用的代码周围添加一个 try-finally
块,以确保即使出现异常也能清除数据。编译器会为托管记录执行默认的 Initialize
初始化和 Finalize
终止化的操作。
10.4
版本后,允许用户自定义 Initialize
和 Finalize
操作,通过运算符重载的方式来进行自定义:
1 2 3 4 5 6
| type TMyRecord = record Value: Integer; class operator Initialize(out Dest: TMyRecord); class operator Finalize(var Dest: TMyRecord); end;
|
加入 Initialize 和 Finalize 操作符重载的记录,会被编译器系统识别为托管记录;编译器会在使用记录中自动加入 try-finally
块