关于变体记录的作用和用法!(30分)

  • 主题发起人 主题发起人 coolqiang
  • 开始时间 开始时间
C

coolqiang

Unregistered / Unconfirmed
GUEST, unregistred user!
经常看到如下的记录形式,好像叫做可变记录,谁能为我说明一下它的作用和用法?
TRect=record
case Integer of
0:(left,Top,Right,Bottom:Integer);
1:(TopLeft,BottomRight:TPoint);
end;
其中的case Integer of这里的Integer是什么意思?后面的0、1分支又表示何意思?
 
就是分支选择啊!

这是数据结构中的经典啊~
根据 Integer的值判断是0还是1,然后执行相关代码~
 
那这个Integer是什么意思?你说判断它的值是0还是1,这个值从何而来?
我知道这是定义一个形式可变的记录,比如
type
TRect=record
case Integer of
0:(left,Top,Right,Bottom:Integer);
1:(TopLeft,BottomRight:TPoint);
end;

var
Rect:TRect;
P1,P2:TPoint;
那么在程序中可以用两种方式使用这个Rect:
1、Rect(100,100,200,200);
2、假设P1(100,100),P2(200,200),那么可以用Rect(P1,P2)
我现在就是要问为什么要case Integer of这么写,Integer是什么意思?
 
A record type can have a variant part, which looks like a case statement. The
variant part must follow the other fields in the record declaration.
To declare a record type with a variant part, use the following syntax.

type recordTypeName = record

fieldList1: type1;
...
fieldListn: typen;
case tag: ordinalType of
constantList1: (variant1);
...
constantListn: (variantn);
end;

The first part of the declaration梪p to the reserved word case梚s the same as
that of a standard record type. The remainder of the declaration梖rom case to
the optional final semicolon梚s called the variant part. In the variant part,

tag is optional and can be any valid identifier. If you omit tag, omit the
colon (:) after it as well.
ordinalType denotes an ordinal type.
Each constantList is a constant denoting a value of type ordinalType, or a comma-delimited list of such constants. No value can be represented more than once in the combined constantLists.
Each variant is a comma-delimited list of declarations resembling the fieldList: type constructions in the main part of the record type. That is, a variant has the form

fieldList1: type1;

...
fieldListn: typen;

where each fieldList is a valid identifier or comma-delimited list of
identifiers, each type denotes a type, and the final semicolon is optional.
The types must not be long strings, dynamic arrays, variants (that is,
Variant types), or interfaces, nor can they be structured types that contain
long strings, dynamic arrays, variants, or interfaces
but they can be
pointers to these types.

Records with variant parts are complicated syntactically but deceptively simple
semantically. The variant part of a record contains several variants which
share the same space in memory. You can read or write to any field of any
variant at any time
but if you write to a field in one variant and then to a
field in another variant, you may be overwriting your own data. The tag, if
there is one, functions as an extra field (of type ordinalType) in the
non-variant part of the record.

Variant parts have two purposes. First, suppose you want to create a record
type that has fields for different kinds of data, but you know that you will
never need to use all of the fields in a single record instance. For example,

type

TEmployee = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Salaried: Boolean of
True: (AnnualSalary: Currency);
False: (HourlyWage: Currency);
end;

The idea here is that every employee has either a salary or an hourly wage,
but not both. So when you create an instance of TEmployee, there is no reason
to allocate enough memory for both fields. In this case, the only difference
between the variants is in the field names, but the fields could just as
easily have been of different types. Consider some more complicated examples:

type

TPerson = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Citizen: Boolean of
True: (Birthplace: string[40]);
False: (Country: string[20];
EntryPort: string[20];
EntryDate, ExitDate: TDate);
end;

type

TShapeList = (Rectangle, Triangle, Circle, Ellipse, Other);
TFigure = record
case TShapeList of
Rectangle: (Height, Width: Real);
Triangle: (Side1, Side2, Angle: Real);
Circle: (Radius: Real);
Ellipse, Other: ();
end;

For each record instance, the compiler allocates enough memory to hold all the
fields in the largest variant. The optional tag and the constantLists (like
Rectangle, Triangle, and so forth in the last example above) play no role in
the way the compiler manages the fields
they are there only for the
convenience of the programmer.
The second reason for variant parts is that they let you treat the same data
as belonging to different types, even in cases where the compiler would not
allow a typecast. For example, if you have a 64-bit Real as the first field in
one variant and a 32-bit Integer as the first field in another, you can assign
a value to the Real field and then read back the first 32 bits of it as the
value of the Integer field (passing it, say, to a function that requires
integer parameters).
 
blbird:
谢谢,我看了半天,大体弄清楚了,但我不明白,当case...of部分没有具体的参数时怎
么来确定使用哪个变体部分?例如:
TEmployee = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Salaried: Boolean of
True: (AnnualSalary: Currency);
False: (HourlyWage: Currency);
end;
这里的case部分是根据Salaried来确定的,那么当出现如下情况:
TRect=record
case Integer of
0:(left,Top,Right,Bottom:Integer);
1:(TopLeft,BottomRight:TPoint);
end;
这里的case部分是没有参数的,我根据什么来决定使用哪个变体部分呢?是不是这时候
随便使用哪个都可以?
 
这里类似C语言里的联合Union,
也就是结构里多个域变量共享一块存储区,
你可以把它只看作一块内存区域:
比如你给的TRect记录体里就是4个整型变量的内存块,
存储数据,当你按第一种方式给域变量赋值后,按该方式引用即可,
若按第二种方式TPoint读出的结果应该不会出错.
 
Integer只是界定符而已,没有什么实际意义
使用直接按照struct的用法即可
 
的确很难理解啊
 
integer是为了保证语法的正确。
case ... of 的constantList1必须是一个integer----有序列的数据类型。

TShapeList = (Rectangle, Triangle, Circle, Ellipse, Other);
中,Rectangle在case中相当于0.Triangle相当于1,只是比直接写成0或1好看,有意义。
 
多人接受答案了。
 
像这样的记录又如何理解呢?
PHostEnt=^THostEnt;
hostent=record
h_name:PChar;
h_aliases:^PChar;
h_addrtype:Smallint;
h_length:Smallint;
case Byte of
0:(h_addr_list:^PChar);
1:(h_addr:^PChar);
end;
ThostEnt=hostent;
真是不明白这些玩意!!
QQ:27191895
 
TRect=record
case Integer of
0:(left,Top,Right,Bottom:Integer);
1:(TopLeft,BottomRight:TPoint);
end;

它以最大的一个分支作为分配的字节,因为共同使用一个连继的内存空间,所以:
Left := 10
top := 20
Right := 30
Botton := 40
那TopLeft(X: 10, Y := 20),它是将上面 L, T, R, B共SizeOf(Integer) * 4字节看成是
SizeOf(TPoint) * 2来看,
P := L, T, R, B的首地址
TopLeft.X := P^;
TopLeft.Y := PInteger(Integer(P) + SizeOf(Integer))^;
类同,其实就是取内存的值。

case Integer of 不一定是Integer,只要是Ordinal类型的值,即可。
注:所有指针所占用的字节数为:4, ^PChar也就是4

一家之言,说错莫怪
 
后退
顶部