A record is a structured data type that consists of a number of elements. Unlike an array, which is merely a group of variables that share the same name and the same data type, a record is a data type that contains elements (fields) of different types. To create a new record, you have to use the reserved word record and declare the fields inside the record block. Field declarations are actually standard variable declarations.
The syntax of a record type declaration is:
type RecordName = record Field_1: DataType; Field_2: DataType; Field_n: DataType; end;
After you create a new record type, you can use it after you declare a variable of the same type:
type TBook = record ISBN: string; Title: string; PageCount: Integer; Authors: array[1..4] of string; end; var Book: TBook;
To access fields in a record, you have to use the dot syntax:
Record.Field
To fill the Book record with data, you can write something like this:
Book.Title := 'Bring Me the Head of Prince Charming'; Book.Authors[1] := 'Roger Zelazny'; Book.Authors[2] := 'Robert Sheckley'; Book.PageCount := 280;
Normally, you always have to write the record name before you can access its fields. But, if you use the reserved word with, you only have to write the record name once. The reserved word with is used to define a block where you can directly access the fields of the specified record.
The syntax of the with block is:
with Record do begin Field_1 := Value; Field_2 := Value; Field_n := Value; end;
The with block enables you to write less code, especially when the record has a large number of fields or when the record name is really long.
with Book do begin Title := 'Bring Me the Head of Prince Charming'; Authors[1] := 'Roger Zelazny'; Authors[2] := 'Robert Sheckley'; PageCount := 280; end;
The following example illustrates how to define record fields in another record and how to use record arrays.
Listing 7-2: Using records
program Project1; {$APPTYPE CONSOLE} uses SysUtils; type TSex = (sxMale, sxFemale); TAuthor = record FirstName: string; MiddleName: string; LastName: string; Age: Integer; Sex: TSex; end; TBook = record ISBN: string; Title: string; PageCount: Integer; Authors: array[1..4] of TAuthor; end; var TownLibrary: array[1..100] of TBook; begin with TownLibrary[1] do begin Title := 'Starship Troopers'; with Authors[1] do begin FirstName := 'Robert'; MiddleName := 'A.'; LastName := 'Heinlein'; Sex := sxMale; end; // with first or only author end; // with first book end.
When you create procedures and functions that accept a record as a parameter, that parameter should be declared as a variable parameter or a constant parameter. If you have to change fields in the record, use a variable parameter. If you only have to read field values, use a constant parameter.
If you use a standard value parameter, the procedure has to make a copy of the entire record every time you call it. In this case, if you pass a value parameter, the procedure has to copy 92 bytes (SizeOf(TBook)). For a constant or variable parameter, the procedure call only has to pass the address of the variable, which is only 4 bytes in size.
procedure DisplayBook(const ABook: TBook); begin WriteLn(ABook.Title); Write(ABook.Authors[1].FirstName, ' ', ABook.Authors[1].LastName); end; var TownLibrary: array[1..100] of TBook; i: Integer; begin for i := Low(TownLibrary) to High(TownLibrary) do DisplayBook(TownLibrary[i]); ReadLn; end.
As you might have noticed, the names of all custom types start with the capital letter T. This is merely a convention, but since it is so widely and consistently used, you should follow it as if it were a rule.