如何使用for循环遍历G1-G4的记录字段?
TrFireGroup = record
idx: integer;
G1: integer;
G2: integer;
G3: integer;
G4: integer;
FGroup: integer;
MstIdx: integer;
Status: byte;
procedure Clear;
end;
答案 0 :(得分:3)
这可能不是一个好主意,但它是可能的。
procedure Test();
var
i: Integer;
rec: TrFireGroup;
GPtr: PInteger;
value: Integer;
begin
// Initialize rec ...
// Get pointer to first G? field
GPtr := @rec.G1;
// Loop over G fields
for i := 0 to 3 do
begin
// Use value G? field here...
// For example: value := GPtr^;
// Increment pointer, thus moving it with four bytes.
Inc(GPtr);
end;
end;
首先获取指针(GPtr
)到rec中的第一个字段。
然后,我们通过取消引用指针(GPtr^
)来使用该值。
最后,将指针递增到下一个值(Inc(GPtr)
)。
请注意,增量是将指针移动到所引用类型的大小。
当我们使用指向Integer(PInteger
)的指针时,Inc
将指针移动到SizeOf(Integer)
,前进到记录中的下一个字段。
同样,这不是一个好习惯。
在这种情况下,指针算法是过度的,除非你在记录中有数百个字段(这是非常罕见的),但如果你真的需要,这是一种方法。
仅供参考,这里有关于Delphi和指针算法指针的非常详细和高质量的解释:
答案 1 :(得分:3)
如果您需要维护现有的记录接口结构以实现兼容性,则可以使用属性来执行此操作。将值存储在数组中允许您枚举它们,并且可以使用现有名称定义属性以直接以现有方式访问值。
program Project1;
{$APPTYPE CONSOLE}
type
TGArray = array[0..3] of integer;
TrFireGroup = record
private
FGArr : TGArray;
public
idx: integer;
FGroup: integer;
MstIdx: integer;
Status: byte;
property G1 : integer read FGArr[0] write FGArr[0];
property G2 : integer read FGArr[1] write FGArr[1];
property G3 : integer read FGArr[2] write FGArr[2];
property G4 : integer read FGArr[3] write FGArr[3];
property GArray : TGArray read FGArr;
end;
var
LFireGroup : TrFireGroup;
j : integer;
begin
LFireGroup.G1 := 1;
LFireGroup.G2 := 3;
LFireGroup.G3 := 5;
LFireGroup.G4 := 7;
for j in LFireGroup.GArray do
WriteLn(j);
ReadLn;
end.
如果您需要将记录布局与二进制兼容(无论出于何种原因),您可以放弃一些整洁和重新排列的东西
TrFireGroup = record
idx: integer;
GArray : TGArray;
FGroup: integer;
MstIdx: integer;
Status: byte;
procedure Clear;
property G1 : integer read GArray[0] write GArray[0];
property G2 : integer read GArray[1] write GArray[1];
property G3 : integer read GArray[2] write GArray[2];
property G4 : integer read GArray[3] write GArray[3];
end;
将GArray
作为公共字段也允许您进行索引编写(而这不可能作为普通属性) - 即:
for i := Low(TGArray) to High(TGArray) do
LFireGroup.GArray[i] := 2*i;
或者,如果您可以放弃for/in
语义,则可以将数组定义为默认属性并直接引用该记录:
TrFireGroup = record
private
FGArr : TGArray;
procedure SetG(index:integer; Value:integer);
function GetG(index:integer) : integer;
public
property G1 : integer read FGArr[0] write FGArr[0];
property G2 : integer read FGArr[1] write FGArr[1];
property G3 : integer read FGArr[2] write FGArr[2];
property G4 : integer read FGArr[3] write FGArr[3];
property GArray[index:integer]:integer read GetG write SetG; default;
end;
procedure TrFireGroup.SetG(index:integer; Value:integer);
begin
FGArr[index] := Value;
end;
function TrFireGroup.GetG(index: Integer) : integer;
begin
result := FGArr[index];
end;
允许你这样做:
for i := Low(TGArray) to High(TGArray) do
LFireGroup[i] := 2*i;
for i := Low(TGArray) to High(TGArray) do
WriteLn(LFireGroup[i]);
答案 2 :(得分:1)
如果您使用的是最近的Delphi版本并且只需要G1..G4的当前值(即不写入它们),您也可以使用此方法:
var
I: Integer;
fg: TrFireGroup;
arr: TArray<Integer>;
begin
...
arr := [fg.G1, fg.G2, fg.G3, fg.G4];
for I in arr do begin
Writeln(I);
end;
...
end;
答案 3 :(得分:1)
恕我直言,如果您不需要二进制兼容性,那么最简单的选择就是使用variant record:
TrFireGroup = record
idx: integer;
FGroup: integer;
MstIdx: integer;
Status: byte;
procedure Clear;
case Integer of
0: (G1: integer; G2: integer; G3: integer; G4: integer);
1: (GArr: array[0..3] of integer);
end;
这相当于旧的Delphi absolute
关键字。阵列和四个G?变量在内存中占有相同的位置。